6

我们正在使用 Dropwizard / Jersey 来构建 Web 服务。资源有路径,方法有子路径。当返回创建的响应(201)时,我们获取的方法的路径被添加到我们提供的位置。当返回一个位置的 OK 状态时(我知道是人为的),一切都很好,并且返回的位置就像我们提供的一样。

我们如何返回一个不是我们方法位置的子路径的位置?

在下面的示例中:访问“http://localhost/foo/bar”(创建状态)以“http://localhost/foo/bar/wibble”的位置响应(注意/foo/bar

而对“http://localhost/foo/baz”(ok 状态)的访问则以“http://localhost/wibble”的位置响应,这正是我们想要的。

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import java.net.URI;

@Path("/foo")
public class FooResource {

    @POST
    @Path("/bar")
    public Response bar() {

        URI uriOfCreatedResource = URI.create("/wibble");
        return Response.created(uriOfCreatedResource).build();
    }

    @POST
    @Path("/baz")
    public Response baz() {

        URI uriOfCreatedResource = URI.create("/wibble");
        return Response.ok().location(uriOfCreatedResource).build();
    }
}
4

3 回答 3

8

万一有人偶然发现这里想知道这一点;我深入研究了泽西岛的代码,看看为什么会发生这种情况。这应该可以解释您的问题和 Carlo 的解决方法。

com.sun.jersey.spi.container.ContainerResponse 包含这个 gem:

private void setHeaders(MultivaluedMap<String, Object> headers) {
    this.headers = headers;
    Object location = headers.getFirst(HttpHeaders.LOCATION);
    if (location != null) {
        if (location instanceof URI) {
            final URI locationUri = (URI)location;
            if (!locationUri.isAbsolute()) {
                final URI base = (statusType.getStatusCode() == Status.CREATED.getStatusCode())
                        ? request.getAbsolutePath() // WHY!?
                        : request.getBaseUri();
                location = UriBuilder.fromUri(base).
                        path(locationUri.getRawPath()).
                        replaceQuery(locationUri.getRawQuery()).
                        fragment(locationUri.getRawFragment()).
                        build();
            }
            headers.putSingle(HttpHeaders.LOCATION, location);
        }
    }
}

换句话说:由于某种原因,有人认为如果响应状态代码是 201,则以不同的方式处理位置标头是一个好主意。就像 Carlo 注意到的那样,使用绝对路径可以避免这个问题。

于 2013-05-28T13:40:18.550 回答
4

在 GlassFish (JavaEE6) 上发生在我身上。我认为这是一个错误,但我从未设法将代码挖掘到实际的 URI 转换......

我找到了一个解决方法:

public Response bar(@Context UriInfo info) {
   URI absoluteURI=info.getBaseUriBuilder().path("/wibble").build();
   return Response.created(absoluteURI).build();
}
于 2012-12-04T13:42:08.167 回答
0

在 Jersey 2.x 中,相关代码被完全重写并移到了另一个地方。在 class 内部org.glassfish.jersey.server.ServerRuntime,在写入响应数据时会调用以下方法:

   private static void ensureAbsolute(final URI location, final MultivaluedMap<String, Object> headers,
                                       final ContainerRequest request) {
        if (location == null || location.isAbsolute()) {
            return;
        }
        // according to RFC2616 (HTTP/1.1), this field can contain one single URI
        headers.putSingle(HttpHeaders.LOCATION, request.getBaseUri().resolve(location));
    }

如前所述,除非应用程序为 Location 标头设置绝对 URI(以类似http:or的模式开头的 URI ftp:),否则 Jersey 会自动在其前面加上请求的基本 URI。

奇怪的是,泽西岛不允许控制或禁用这种行为。

于 2015-04-08T14:17:31.090 回答