Spring HATEOAS和带Eureka的Ribbon - 创建链接中的主机名

时间:2016-12-04 21:29:30

标签: spring spring-mvc spring-cloud spring-hateoas spring-cloud-netflix

我使用Spring HATEOAS构建和访问REST服务。该服务使用eureka服务器注册,我使用Ribbon(通过@LoadBalanced RestTemplate)来调用它。

默认情况下,会对已解析实例的主机名(在Host标头中)发出请求。这导致Spring HATEOAS中的LinkBuilder为该主机生成链接。当Ribbon发出跟踪链接的请求时,它会尝试再次在eureka中查找链接主机名,当然没有结果。

解决这种情况的最佳水平是什么?收到带有第一个结果的链接后,我想将以下请求直接指向同一个服务实例是可以接受的,我仍然觉得对符号服务名称的所有请求都会更好。

是否可以将Ribbon配置为在Host标头中使用该服务名称发出请求(假设目标服务中没有虚拟主机,这似乎是一个有效的假设)?

否则是否可以在HATEOAS中为链接构建器设置规范的基本URL? (将所有链接定义为完整字符串对我来说是不可接受的)

我现在的解决方案/解决方法是在请求根资源时显式设置X-Forwarded-Host标头。这有效,但有点冗长和繁琐。

Traverson traverson = new Traverson(URI.create("http://photo-store/"), MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8, MediaTypes.HAL_JSON).setRestOperations(imageService);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("X-Forwarded-Host", "photo-store");
String original = this.traverson.follow("image:original").withHeaders(httpHeaders).asTemplatedLink().expand(photoId).getHref();

(旁边的问题:我可以像这样重写Host标题,还是在Ribbon或RestTemplate中对它进行特殊处理?)

我觉得应该有一个更具声明性或约定或配置的方式来处理这个问题。有吗?

2 个答案:

答案 0 :(得分:1)

我也面临同样的问题。我通过添加拦截器来解决它,它为每个请求添加了X-Forwarded-Host标头。

@Bean
@LoadBalanced
RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setInterceptors(singletonList((ClientHttpRequestInterceptor) (request, body, execution) -> {
        request.getHeaders().add("X-Forwarded-Host", request.getURI().getHost());
        return execution.execute(request, body);

    }));
    return restTemplate;
}

答案 1 :(得分:0)

我正在使用我自己的linkBuilder,它从属性中获取服务的名称并将其用作主机名。这是非常基本的,但是易于使用和实现。如果您想使用整个春季的风俗链接发现魔术酱,则需要做更多的事情。但是现在我正在寻找自己更适合Spring Hateoas 1.x的解决方案,所以也许我很快就会找到一个更好的答案。

快速而肮脏的方式:

@Component
public class MyLinkBuilder {

    @Value("${spring.application.name}")
    private String servicename;

    public Link getLink(String path) {
        String root = "http://" + servicename;
        return new Link(root + path);
    }


    public Link getLink(String path, String rel) {
        return getLink(path, LinkRelation.of(rel));
    }

    public Link getLink(String path, LinkRelation rel) {
        String root = "http://" + servicename;
        return new Link(root + path, rel);
    }
}