Java 不允许PUT使用Jersey路径正则表达式导致方法

Java 不允许PUT使用Jersey路径正则表达式导致方法,java,rest,jersey,Java,Rest,Jersey,我正在测试Jersey,当我调用PUT时,我似乎不明白为什么我得到了一个不允许的405方法: $ curl -v --header "Content-Type: image/jpeg" --upload-file /Users/andy/Desktop/test.jpg http://localhost:9090/images/abcde * About to connect() to localhost port 9090 (#0) * Trying 127.0.0.1... connec

我正在测试Jersey,当我调用
PUT
时,我似乎不明白为什么我得到了一个不允许的
405方法:

$ curl -v --header "Content-Type: image/jpeg" --upload-file /Users/andy/Desktop/test.jpg http://localhost:9090/images/abcde
* About to connect() to localhost port 9090 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 9090 (#0)
> PUT /images/abcde HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:9090
> Accept: */*
> Content-Type: image/jpeg
> Content-Length: 48198
> Expect: 100-continue
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 405 Method Not Allowed
< Content-Type: text/html; charset=iso-8859-1
< Date: Mon, 20 Aug 2012 18:35:59 GMT
< Allow: GET,OPTIONS,HEAD
< Transfer-Encoding: chunked
@Singleton@Path(“图像”)
公共类图像资源{
私有静态最终字符串IMAGE_ID_PATH_PARAM=“{imageId:[A-Za-z0-9\\\-]+}”;
私有静态最终字符串扩展名\u PATH\u PARAM=“{扩展名:(\\.[A-Za-z]+)?}”;
@获取@Path(图像\u ID\u路径\u参数+扩展\u路径\u参数)
@产生(“图像/*”)
公共响应getImage(@PathParam(“imageId”)字符串imageId,
@PathParam(“扩展”)字符串扩展,@QueryParam(“mods”)字符串(mods){
...
}
@放置@Path(图像\u ID\u路径\u参数)
@消费(“图像/*”)
公共响应putImage(@PathParam(“imageId”)字符串imageId,文件图像){
...
}
}
PUT
仅当我将
@GET
路径设置为
@path(IMAGE\u ID\u path\u PARAM)
时才起作用。当我添加扩展部件时,我得到一个
405
状态代码
GET
似乎在这两种情况下都有效。以下是失败的
放置的输出:

$ curl -v --header "Content-Type: image/jpeg" --upload-file /Users/andy/Desktop/test.jpg http://localhost:9090/images/abcde
* About to connect() to localhost port 9090 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 9090 (#0)
> PUT /images/abcde HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:9090
> Accept: */*
> Content-Type: image/jpeg
> Content-Length: 48198
> Expect: 100-continue
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 405 Method Not Allowed
< Content-Type: text/html; charset=iso-8859-1
< Date: Mon, 20 Aug 2012 18:35:59 GMT
< Allow: GET,OPTIONS,HEAD
< Transfer-Encoding: chunked
$curl-v--标题“内容类型:image/jpeg”--上传文件/Users/andy/Desktop/test.jpghttp://localhost:9090/images/abcde
*即将连接()到本地主机端口9090(#0)
*正在尝试127.0.0.1。。。有联系的
*已连接到本地主机(127.0.0.1)端口9090(#0)
>PUT/images/abcde HTTP/1.1
>用户代理:curl/7.21.4(universal-apple-darwin11.0)libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
>主机:localhost:9090
>接受:*/*
>内容类型:图像/jpeg
>内容长度:48198
>预期:100人继续
> 

我也尝试过在没有
@的情况下进行测试,生成
@使用
注释,但它也不起作用。

让我们看看发送请求时会发生什么

情况1:不延长 您的方法如下所示:

    @GET @Path(IMAGE_ID_PATH_PARAM)
    @Produces("image/*")
    public Response getImage(@PathParam("imageId") String imageId,
        @PathParam("extension") String extension, @QueryParam("mods") String mods) {
        ...
    }

    @PUT @Path(IMAGE_ID_PATH_PARAM)
    @Consumes("image/*")
    public Response putImage(@PathParam("imageId") String imageId, File image) {
        ...
    }
@GET @Path(IMAGE_ID_PATH_PARAM + EXTENSION_PATH_PARAM)
@Produces("image/*")
public Response getImage(@PathParam("imageId") String imageId,
    @PathParam("extension") String extension, @QueryParam("mods") String mods) {
    ...
}

@PUT @Path(IMAGE_ID_PATH_PARAM)
@Consumes("image/*")
public Response putImage(@PathParam("imageId") String imageId, File image) {
    ...
}
当您发送以下请求时:

PUThttp://localhost:9090/images/abcde

首先,Jersey查找URI有问题的资源:
http://localhost:9090/images/abcde

找到资源后,它会检查可以使用哪些方法访问它。 在这种情况下,您有一个路径由
IMAGE\u ID\u path\u PARAM
定义的资源。可通过
GET
PUT
请求访问此资源。就像您使用注释指定的那样

情形2:扩展添加到
getImage
您现在看到的方法如下所示:

    @GET @Path(IMAGE_ID_PATH_PARAM)
    @Produces("image/*")
    public Response getImage(@PathParam("imageId") String imageId,
        @PathParam("extension") String extension, @QueryParam("mods") String mods) {
        ...
    }

    @PUT @Path(IMAGE_ID_PATH_PARAM)
    @Consumes("image/*")
    public Response putImage(@PathParam("imageId") String imageId, File image) {
        ...
    }
@GET @Path(IMAGE_ID_PATH_PARAM + EXTENSION_PATH_PARAM)
@Produces("image/*")
public Response getImage(@PathParam("imageId") String imageId,
    @PathParam("extension") String extension, @QueryParam("mods") String mods) {
    ...
}

@PUT @Path(IMAGE_ID_PATH_PARAM)
@Consumes("image/*")
public Response putImage(@PathParam("imageId") String imageId, File image) {
    ...
}
同样,您发送相同的请求:
PUThttp://localhost:9090/images/abcde

Jersey再次找到与URL匹配的第一个资源。资源由
getImage
方法表示,就像第一次一样。这一次,
@GET
注释与您的请求不匹配。和以前一样,Jersey尝试为资源找到另一个可用的方法,以匹配您的请求

但是,这次没有找到这样的方法,因此它返回405

发生这种情况的原因是
getImage
putImage
方法现在代表不同的资源。如果仔细观察,路径可以如下所示(为了清楚起见,我将省略正则表达式):

@Path({imageId}{extension})
for
getImage

@Path({imageId})
用于
putImage

考虑到正则表达式,这两条路径可以成为相同的东西,但Jersey仍然将它们视为单独资源的标识符

如果您查看Jersey生成的WADL(如果您不熟悉标准,请随意查看)文件(应在
http://localhost:9090/application.wadl
),您会注意到这正是正在发生的事情

<application xmlns="http://research.sun.com/wadl/2006/10">
<resources base="http://localhost:9090/">
<resource path="images">
  <resource path="{imageId : [A-Za-z0-9_\-]+}">
    <param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="imageId" style="template" type="xs:string"/>
    <method id="putImage" name="PUT">
      <request>
        <representation mediaType="image/*"/>
      </request>
      <response>
        <representation mediaType="*/*"/>
      </response>
    </method>
  </resource>
  <resource path="{imageId : [A-Za-z0-9_\-]+}{extension : (\.[A-Za-z]+)?}">
    <param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="extension" style="template" type="xs:string"/>
    <param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="imageId" style="template" type="xs:string"/>
    <method id="getImage" name="GET">
      <request>
        <param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="mods" style="query" type="xs:string"/>
      </request>
      <response>
        <representation mediaType="image/*"/>
      </response>
    </method>
  </resource>
</resource>
</resources>
</application>
在这种情况下,
images
正好有一个子资源,而子资源又有两种可用的方法


就我个人而言,我发现自动生成WADL是泽西的一大特色。这是一个很好的方法,可以在不花太多时间使用curl或其他REST客户端的情况下查看资源方法的情况。

您是否尝试将
扩展路径参数添加到
putImage
?你不能用它。嗯……我刚试过,它很管用!你能解释一下为什么会这样吗?非常令人困惑!如果你把它作为一个答案贴出来,我会接受的。我想我知道原因,但我必须亲自检查以确定。我会回来发布一个答案。来自Spring MVC的背景,泽西岛的这种行为感觉有点拘束。似乎没有相应GET的PUT是不可能的。但是,如果没有这些规则,WADL生成可能是不可能的,也不能保证接口是静态的。无论如何,谢谢你的详细解释,汤姆@没有相应GET的PUT是完全有效和可能的。小心那些小路。在这种情况下,存在模棱两可的余地。只要保持路径相同或完全不同(在某些情况下不可能混淆),一切都会好起来。我对Spring不是很熟悉,但了解它是我待办事项清单上最重要的事情之一。