首页 > 解决方案 > Jersey 如何确定应用程序的基本 URI?

问题描述

我有一个在 tomcat 中运行的 java 应用程序。在应用程序的一个端点中,我想返回 See-Other 类型的 HTTP 响应。

@GET
@Path("logout")
@Produces(MediaType.TEXT_HTML)
public Response logOut(@Context HttpServletRequest request) throws URISyntaxException {
    // logout logic omitted
    Response.ResponseBuilder response = Response.seeOther(new URI("../jsp/login.jsp"));
    return response.build();
}

当我在本地机器上测试它时,一切正常。然而,在生产系统上,泽西似乎无法从相对路径“../jsp/login.jsp”中解析正确的主机名。虽然主机名为 myhost,但相对路径解析为 http://localhost:7080/myapplication/jsp/login.jsp。

new URI("../jsp/login.jsp") 返回一个对象,其中所有字段都为空,并且只有 path="../jsp/login.jsp"。由于这个原因,行为的根源必须在 Response 类中。我检查了文档并发现 Response.seeOther 调用了 Response.location 方法。该文件指出

如果提供了相对 URI,它将通过相对于应用程序的基本 URI 解析它被转换为绝对 URI

有谁知道 Jersey 如何确定应用程序的基本 URI?tomcat中是否有一些配置文件或我设置错误的环境变量?

标签: javahttptomcatjerseyjax-rs

解决方案


应用程序的基本 URI 是使用对象的属性计算的HttpServletRequest,其形式为:

<scheme>://<serverName>:<serverPort>/<contextPath><servletPath>/

和通常由 HTTP 客户端提供,而其余部分由 Tomcat 或您的应用程序的配置修复<serverName><serverPort>

  • <scheme>使用 a 的同名属性配置<Connector>(参见Tomcat 的文档),或者可以由RemoteIpValve(参见文档)设置,
  • <serverName>由 HTTP 客户端提供,但可以使用proxyName连接器的属性覆盖,
  • <serverPort>由 HTTP 客户端提供,但可以使用proxyPort连接器的属性或由RemoteIpValve,
  • <contextPath>取决于您如何部署应用程序(例如,它取决于webapps目录中 WAR 文件的名称),
  • <servletPath>web.xml描述符中或通过@ApplicationPath注解配置。

在您的生产环境中可能发生的情况是 Tomcat 位于反向代理之后。要在这种情况下正确配置基本 URI,您有两种选择:

  1. 在您的 ,上静态配置 ,scheme和的正确值secureproxyNameproxyPort<Connector>
  2. 使用RemoteIpValve和 配置代理服务器发送原始Host标头并添加X-Forwarded-ForX-Forwarded-Proto标头。

如果您的代理向 Tomcat 转发不同类型的请求(例如 HTTP 和 HTTPS 请求),那么这RemoteIpValve是您唯一的选择。

备注: base URI 也可以基于请求 URI,如果您将ServerProperties.LOCATION_HEADER_RELATIVE_URI_RESOLUTION_RFC7231属性设置为true:cf。这个问题


推荐阅读