Jersey HTTP Delete、Put响应状态:405(方法不允许)

huangapple go评论96阅读模式
英文:

Jersey HTTP Delete,Put Response Status: 405 (Method Not Allowed)

问题

Day 1: 为删除操作添加了以下REST端点。

@Path("/company/v1/department")
@Component
public class ManageResource {

@DELETE
@Path("/{identifier}/{identifier_value}/employee")
public void delete(@PathParam("identifier") String identifier,
                   @PathParam("identifier_value") final String identifierValue,
                   @QueryParam("age") final String age) {

 //删除操作
}
}

我可以使用以下请求在 Postman 中调用 DELETE 端点:

DELETE: http://localhost:8080/company/v1/department/name/baner/employee?age=50

Day 2: 在相同的资源中为更新操作添加了以下REST端点。

@Path("/company/v1/department")
@Component
public class ManageResource {

@DELETE
@Path("/{identifier}/{identifier_value}/employee")
public void delete(@PathParam("identifier") String identifier,
                   @PathParam("identifier_value") final String identifierValue,
                   @QueryParam("age") final String age) {
   
//删除操作
}

@PUT
@Path("/empid/{value}/employee")
@Consumes(MediaType.APPLICATION_JSON)
public void update(@PathParam("value") final String identifierValue,
                   @RequestBody final EmployeeUpdateRequest request) {
   
//更新操作
}
}

在添加了这个新端点后,我可以使用以下请求在 Postman 中调用 PUT:

PUT: http://localhost:8080/company/v1/department/empid/epid-123/employee
{
//Json 请求体
}

但是,当我尝试调用删除端点时,会出现 405(方法不允许)错误。
如果我注释掉新的 PUT 方法,那么删除方法就能正常工作。
另外,如果我将 PUT 方法的 Path 替换为 /{identifier}/{identifier_value}/employee,那么删除和 PUT 方法都能正常工作。

我正在使用 Jersey 1.19 与 tomcat。
有人能帮我解决这个问题吗?

英文:

Day 1: Added below rest endpoint for delete operation.

@Path("/company/v1/department")
@Component
public class ManageResource {

@DELETE
@Path("/{identifier}/{identifier_value}/employee")
public void delete(@PathParam("identifier") String identifier,
                   @PathParam("identifier_value") final String identifierValue,
                   @QueryParam("age") final String age) {

 //delete operation
}
}

I was able to invoke DELETE endpoint using postman with below request:

DELETE: http://localhost:8080/company/v1/department/name/baner/employee?age=50

Day 2: Added below rest endpoint for the update operation in the same resource.

@Path("/company/v1/department")
@Component
public class ManageResource {

@DELETE
@Path("/{identifier}/{identifier_value}/employee")
public void delete(@PathParam("identifier") String identifier,
                   @PathParam("identifier_value") final String identifierValue,
                   @QueryParam("age") final String age) {
   
//delete operation
}

@PUT
@Path("/empid/{value}/employee")
@Consumes(MediaType.APPLICATION_JSON)
public void update(@PathParam("value") final String identifierValue,
                   @RequestBody final EmployeeUpdateRequest request) {
   
//update operation
}
}

After adding this new endpoint, I am able to invoke PUT using postman with below request:

PUT: http://localhost:8080/company/v1/department/empid/epid-123/employee
{
//Json request body
}

But when I try to invoke Delete endpoint it is giving me 405 (Method Not Allowed) error.
If I comment my new Put method, then the Delete method works fine.
Also, if I replace Path for Put method to "/{identifier}/{identifier_value}/employee" then both Delete and Put method works fine.

I am using Jersey 1.19 with tomcat.
Can someone help me with this?

答案1

得分: 1

你们的路径存在冲突。让我尝试解释一下:

DELETE = /{identifier}/{identifier_value}/employee 
PUT = /empid/{value}/employee

这意味着当我们从左到右评估路径时,我们可以有以下两种情况:
{identifier} 可以是任何内容,或者
"empid" 是一个固定的字符串

Jersey 总是尝试找到 REST 终端点的“最佳”匹配。它通过从左到右评估路径来实现这一点。
固定字符串始终优先于随机变量!

基本上这意味着当您想调用 DELETE 时,不能在变量"{identifier}"中使用值"empid",因为这样就已经超出了范围。

所以对于 DELETE 调用,

http://localhost:8080/company/v1/department/empid/empid-123/employee

将无法工作,因为 Jersey 必须做出决定,即请求中的"empid" 是否与"{identifier}" (DELETE) 或 "empid" (PUT) 匹配。并且正如我上面尝试解释的,固定字符串具有更高的优先级。
相反地,任何其他 DELETE 请求,例如:

http://localhost:8080/company/v1/department/{identifier}/empid-123/employee

并且

{identifier} != "empid"

将可以工作。

可能的解决方案:

使您的 REST 终端点面向资源

DELETE:
/employee/{employee-id}

PUT:
/employee/{employee-id}

请注意,这些终端点是相同的,因为除了大多数系统中的 ID 外,没有需要用于标识实体的其他信息。

英文:

Your Paths are in conflict with each other. Let me try to explain:

DELETE = /{identifier}/{identifier_value}/employee 
PUT = /empid/{value}/employee

That means when we evaluate the path from left to right, we can either have
{identifier} which is anything or
"empid" which is a fixed string

Jersey always tries to find the "most perfect" match for a REST endpoint. It does so by evaluating the path from left to right.
Fixed strings always take precedence before random variables!

Basically that means when you want to call a DELETE, you cannot have the value "empid" for the variable "{identifier}" because then you are already out-of-scope

So the DELETE call to

http://localhost:8080/company/v1/department/empid/empid-123/employee

will not work as Jersey had to make a decision whether "empid" in the request matches "{identifier}" (DELETE) or "empid" (PUT). And as i tried to explain above, fixed strings take a higher priority.
In contrast, any other DELETE request where

http://localhost:8080/company/v1/department/{identifier}/empid-123/employee

and

{identifier} != "empid"

works.

Possible solution:

make your rest endpoints resource-oriented

DELETE:
/employee/{employee-id}

PUT:
/employee/{employee-id}

Notice how the endpoints are identical, since other than the ID in most systems, no information is needed to identify an entity.

huangapple
  • 本文由 发表于 2020年8月27日 08:43:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63607586.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定