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

请考虑以下代码,将 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);

它通知客户端已创建新的“事物”,并且可以在 URL 上找到它 。问题是这个URL是相对的。这对于 JSP 来说是完美的,JSP 可以按如下方式编写:/app/things?id=42

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

这将产生以下 HTML:

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

这就是我们想要的Web应用程序。

但我不认为这是我们想要的201响应位置标头。HTTP 规范指出

14.30 地点

“位置响应标头”字段用于将收件人重定向到 Request-URI 以外的位置,以便完成请求或标识新资源。对于 201 (Created) 响应,“位置”是由请求创建的新资源的位置。对于 3xx 响应,位置应指示服务器用于自动重定向到资源的首选 URI。字段值由单个绝对 URI 组成。

       Location = "Location" ":" absoluteURI

例如:

       Location: http://www.w3.org/pub/WWW/People.html

我的问题是,我如何以正确的方式将该相对 URL 转换为位置标头的 abosolute URL。

我不相信使用:

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

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


答案 1

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

请注意,RFC 7231 现在在规范中包含相对 URI有关如何处理相对 URI 的其他答案,请参阅其他答案。


答案 2

遗憾的是,Servlet API 没有提供直接返回绝对 URL 的方法,该方法最多返回上下文根目录。为此,我曾多次使用getRequestURL()getRequestURI()getContextPath()的组合

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

推荐