1

我正在测试泽西岛,但我似乎无法弄清楚为什么405 Method Not Allowed我打电话时会得到一个PUT

@Singleton @Path("images")
public class ImageResource {
    private static final String IMAGE_ID_PATH_PARAM = "{imageId : [A-Za-z0-9_\\-]+}";
    private static final String EXTENSION_PATH_PARAM = "{extension : (\\.[A-Za-z]+)?}";

    @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) {
        ...
    }
}

PUT仅当我将@GET路径设置为@Path(IMAGE_ID_PATH_PARAM). 当我添加扩展部分时,我得到一个405状态码。GET似乎在这两种情况下都有效。这是失败的输出PUT

$ 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

我也尝试过没有@Producesand@Consumes注释的测试,它也没有工作。

4

1 回答 1

3

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

情况一:没有延期

您的方法如下所示:

    @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) {
        ...
    }

当您发送以下请求时:

PUT http://localhost:9090/images/abcde

首先,Jersey 查找具有相关 URI 的资源: http://localhost:9090/images/abcde

找到资源后,它会检查可以使用哪些方法来访问它。在这种情况下,您有一个资源,其路径由IMAGE_ID_PATH_PARAM. 这个资源可以被一个GET或多个PUT请求访问。就像您在注释中指定的一样。

情况2:扩展添加到getImage

你的方法现在看起来像这样:

@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) {
    ...
}

同样,您发送相同的请求: PUT http://localhost:9090/images/abcde

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

但是,这一次没有找到这样的方法,所以它返回 405。

发生这种情况的原因是方法getImageputImage现在代表不同的资源。如果你仔细看,路径可以这样读取(为了清楚起见,我将省略正则表达式):

@Path({imageId}{extension})为了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有两个独立的子资源,每个子资源都有一个方法。

解决方案

EXTENSION_PATH_PARAM段添加到putImage@Path注解会导致这两个方法再次映射到单个资源,因此问题消失了。由于正则表达式使这部分是可选的,因此您可以随意省略它并假装它不存在。

在生成的 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_\-]+}{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="putImage" name="PUT">
          <request>
            <representation mediaType="image/*"/>
          </request>
          <response>
            <representation mediaType="*/*"/>
          </response>
        </method>
        <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 的自动生成是 Jersey 的一个很棒的功能。这是一种查看资源方法发生情况的好方法,无需花费太多时间使用 curl 或其他 REST 客户端。

于 2012-08-20T19:48:05.687 回答