9

Spring HATEOAS 提供了方便ControllerLinkBuilder地创建到控制器方法的链接,这些链接将作为返回给客户端的 JSON/XML 中的 href 添加。例如:

resource.add(linkTo(methodOn(FooController.class)
    .findFoo(entity.getClient().getId()))
    .withRel("show"));

...可能会生成 JSON 有点像:

{
  "name":"foo", 
  "links":[
    {"rel":"show","href":"http://111.11.11.111:28080/foos/1"}
  ]
}

然而...

我倾向于通过反向代理访问我的服务。我想大多数人可能会。这让我可以在不同的端口上运行多个服务,但让我可以通过相同的基本 URL 访问它们。不幸的是,通过代理访问意味着 Spring HATEOAS 生成的 URL 不是对访问资源有效的 URL。

现在我可以对链接进行硬编码,但这相当脆弱。根据ControllerLinkBuilder我的控制器配置生成 URL 对我@RequestMapping来说很有价值,因为它避免了我的链接与现实不同步的风险。

所以我想知道是否有一个属性可以用来强制主机和端口值。我正在使用 Spring Boot,因此理想情况下我可以application.properties在每个环境中添加到文件中的属性。

笔记:

由于这个问题似乎是由 Spring 中的错误引起的,我应该指出我使用的是 Spring Boot 1.0.2.RELEASE。

4

2 回答 2

5

我最初提出的问题的纯粹答案似乎涉及编写我自己的ControllerLinkBuilder实现,它可以选择基于我设置的环境变量构建 URL。我可能会这样做。

但是,我试图强制 URL 的原因是ControllerLinkBuilder. 值得注意的是,这个 bug 是从ServletUriComponentsBuilder.

String scheme = request.getScheme();

// The port number retrieved here is the port set by server.port
int port = request.getServerPort();
String host = request.getServerName();

String header = request.getHeader("X-Forwarded-Host");

if (StringUtils.hasText(header)) {
    String[] hosts = StringUtils.commaDelimitedListToStringArray(header);
    String hostToUse = hosts[0];
    if (hostToUse.contains(":")) {
        String[] hostAndPort = StringUtils.split(hostToUse, ":");
        host  = hostAndPort[0];

        // Note that the port is set if there is a ":" in the address.
        port = Integer.parseInt(hostAndPort[1]);
    }
    else {
        host = hostToUse;
    }
}

ServletUriComponentsBuilder builder = new ServletUriComponentsBuilder();
builder.scheme(scheme);
builder.host(host);

// Here lies the bug...
if ((scheme.equals("http") && port != 80) || (scheme.equals("https") && port != 443)) {
    builder.port(port);
}

基本上,端口仅在server.port不是 80 或 443 时设置,而不是基于用于请求的端口。这意味着如果X-Forwarded-Host为方案使用默认端口(因此在“:”之后没有任何内容),则将使用应用程序端口而不是默认端口。

于 2014-06-12T12:41:20.103 回答
2

Spring-Boot 使用旧版本的 Spring-HATEOAS,我认为是 .11 他们添加了对 X-Forwarded-Port 和 X-Forwarded-Ssl 标头的支持,只需将该显式版本添加到您的 POM 并且如果您的代理正在执行正确的事情并添加这些标题你应该很高兴。

此外,如果您的代理可以配置为不重写 HOST 标头,则内置控制器链接构建器将正常工作。

于 2014-06-21T06:45:54.640 回答