首页 文章

在Java Servlet应用程序中为HTTP 201响应设置Location标头的正确方法是什么

提问于
浏览
32

请考虑以下代码向客户端发送HTTP 201“创建”响应:

String url = "/app/things?id=42"; // example
    response.setStatus(HttpServletResponse.SC_CREATED);
    response.setContentType("text/plain");
    response.setHeader("Location", url);
    response.getWriter().print(url);

它通知客户端已创建新的"thing",并且可以在URL /app/things?id=42 找到它 . 问题是这个URL是相对的 . 这对于JSP来说是完美的,可以写成如下:

<img src="<c:url value="/things?id=42" />" />

哪个会产生以下HTML:

<img src="/app/things?id=42" />

这是我们想要的网络应用程序 .

但我不相信这是我们想要的201响应位置 Headers . HTTP规范states

14.30位置Location response-header字段用于将收件人重定向到Request-URI以外的位置,以完成请求或标识新资源 . 对于201(已创建)响应,Location是请求创建的新资源的位置 . 对于3xx响应,位置应该应该指示服务器自动重定向到资源的首选URI . 字段值由单个绝对URI组成 . Location =“Location”“:”absoluteURI
一个例子是:位置:http://www.w3.org/pub/WWW/People.html

我的问题是如何以适当的方式将servlet的相对URL转换为Location头的绝对URL .

我不相信使用:

request.getServerName() + ":" + request.getServerPort() + url;

是正确的解决方案 . 应该有一个生成正确输出的标准方法(以便可以应用URL重写等) . 我不想创建一个hack .

5 回答

  • 2

    如果您使用的是JAX RS, javax.ws.rs.core.Response 中有一个方法automatically converts relative URLs

    public static Response.ResponseBuilder created(java.net.URI location)为创建的资源创建一个新的ResponseBuilder,使用提供的值设置location头 . 参数:location - 新资源的URI . 如果提供了相对URI,则通过相对于请求URI解析它,将其转换为绝对URI .

    但请注意,JAX RS实现CXF中存在一个错误leads to incorrect absolute URLs .

  • 4

    你可以试试

    new URL(new URL(request.getRequestURL().toString()), url).toString();
    

    对于任何 .. 或其他奇怪的规范化,至少应该是明智的 . 除此之外,我不比字符串操作好得多 .

  • 4

    只需发送绝对路径 . 对绝对URI的限制是RFC 2616中的已知缺陷,将在HTTPbis中修复(请参阅http://trac.tools.ietf.org/wg/httpbis/trac/ticket/185) .

    请注意RFC 7231 now includes relative URIs in the spec. 请参阅有关如何处理相对URI的其他答案 .

  • 4

    决定采用Julian Reschke的建议并违反规范!至少我添加了以下评论:

    /* Note: strictly speaking (per section 14.30 of RFC 2616), the Location header 
             * requires an *absolute URI*. However, in practice, many web 
             * applications send an *absolute path* instead. This is interoperable, 
             * that is, works in popular web browsers  (according to 
             * http://en.wikipedia.org/wiki/HTTP_location).
             * 
             * As the information required to set the Location header to an absolute URI
             * is not generally available to a Servlet, we go with the flow and send
             * an absolute path instead (in violation of RFC 2616).
             * 
             * There is an issue filed with Hypertext Transfer Protocol Bis (httpbis) 
             * working group to resolve this problem here:
             * http://trac.tools.ietf.org/wg/httpbis/trac/ticket/185
             */
            response.setHeader("Location", url);
    

    我不想自己发送绝对URI的原因是因为我在负载均衡器和其他 生产环境 基础设施背后遇到了问题 . 虽然在开发模式下“http:// localhost:8080 / foo”趋于正常工作:))

    现在接受朱利安的答案......

  • 20

    不幸的是,servlet API没有提供直接将绝对URL返回到上下文根的方法 . 为此我有几次不得不使用getRequestURL()getRequestURI()getContextPath()的组合 .

    String absoluteContextRootURL = request.getRequestURL().toString().replace(request.getRequestURI().substring(1), request.getContextPath());
    

相关问题