我正在测试泽西岛,当我打电话给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
我也尝试过没有@Produces
和@Consumes
注释的测试,但它也没有用。
答案 0 :(得分: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
请求访问此资源。就像你用注释一样指定。
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
再一次,泽西岛找到了与URL匹配的第一个资源。资源由getImage
方法表示,就像第一次一样。这次,@GET
注释与您的请求不符。就像以前一样,Jersey试图找到另一种可用于该资源的方法,以便匹配您的请求。
但是,这次没有找到这样的方法,因此返回405。
发生这种情况的原因是方法getImage
和putImage
现在代表不同的资源。如果仔细观察,可以像这样读取路径(为了清楚起见,我将省略正则表达式):
@Path({imageId}{extension})
的 getImage
和
@Path({imageId})
的 putImage
虽然考虑到正则表达式,这两条路径可以变成同样的东西,但泽西岛仍将它们视为单独资源的标识符。
如果您看一下WADL(如果您不熟悉标准的here,请随意查看)(由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
的{{1}}注释会导致这两种方法再次映射到单个资源,因此问题就会消失。由于正则表达式使该部分可选,因此您可以省略它并假装它不存在。
在生成的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客户端的情况下查看资源方法发生的情况。