有没有办法为Spring HATEOAS`ControllerLinkBuilder`设置主机和端口?

Ste*_*eve 6 spring-hateoas spring-boot

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

resource.add(linkTo(methodOn(FooController.class)
    .findFoo(entity.getClient().getId()))
    .withRel("show"));
Run Code Online (Sandbox Code Playgroud)

...可能会生成JSON,如下所示:

{
  "name":"foo", 
  "links":[
    {"rel":"show","href":"http://111.11.11.111:28080/foos/1"}
  ]
}
Run Code Online (Sandbox Code Playgroud)

然而...

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

现在,我可以对链接进行硬编码,但这非常脆弱。具有ControllerLinkBuilder基于我的控制器生成URL @RequestMapping配置对我很有用,因为它避免了我的链接获得同步的与现实的风险。

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

注意:

由于此问题似乎是由Spring中的错误引起的,所以我可能应该指出,我使用的是Spring Boot 1.0.2.RELEASE。

Ste*_*eve 5

我最初提出的问题的一个纯粹答案似乎涉及编写我自己的ControllerLinkBuilder实现,该实现可以选择根据我设置的环境变量来构建URL。我可能会那样做。

但是,我尝试强制使用URL的原因是中存在一个错误ControllerLinkBuilder。值得注意的是,此错误是从中复制的代码中的错误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);
}
Run Code Online (Sandbox Code Playgroud)

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