将 Zuul、Hystrix(和 Feign)与 Spring Cloud HATEOAS 一起使用时如何转发 headers?
How to forward headers when using Zuul, Hystrix (and Feign) with Spring Cloud HATEOAS?
上下文
我的micro-services应用是基于spring-cloud
:前面配置了一个zuul
网关micro-services:service-a 和 service-b.
我的一个 API 要求 service-a 请求 service-b;我为此使用 feign
。
Zuul 将 X-FORWARDED-*
headers 发送到服务,以便他们正确重写 HATEOAS 链接(当服务配置为 ForwardedHeaderFilter
时)。
我的问题是服务使用 Feign
相互通信,这依赖于 Hystrix
。
Hystrix
为每个请求创建一个新线程(我们不使用 SEMAPHORE 配置),因此 Spring 的 RequestContextHolder
中的请求在来自 [=59= 的 Feign 请求中丢失了]service-a 到 service-b,我不能再用 feign
拦截器丰富 feign
请求,因为原始请求丢失。
一些潜在的解决方案
Spring 现在直接支持使用参数 hystrix.shareSecurityContext: true
转发授权令牌
没有任何 "out of the box" 配置让 Hystrix 在线程之间共享请求。
一个解决方案可能是 implement my own HystrixConcurrencyStrategy
,它是 netflix.hystrix 的 class。
我最近的发现是这个 Pull Request 已经发送到 spring-cloud-netflix,但不幸的是没有集成。
我可以尝试复制Pull request的代码,然后创建一个bean,就像"eacdy"写的那样:
@Bean
public RequestAttributeHystrixConcurrencyStrategy hystrixRequestAutoConfiguration() {
return new RequestAttributeHystrixConcurrencyStrategy();
}
是否有更简单的解决方案来将 headers 从 Zuul
转发到 Hystrix
?
我想在使用相互通信的 Zuul
、Hystrix
和 HATEOAS
micro-services 时,我尝试做的是非常标准的,所以也许有些东西已经存在(但我找不到)?
谢谢!
我认为这是很常见的事情,但经过大量研究后,我找不到一种方法来自动转发 X-FORWARDED-*
headers 和 Feign
和 Hystrix
.
因此,我寻找了另一种有效且非常干净的解决方案:
- 在从service-a到service-b的
Feign
客户端中,我声明了一个特定的配置"ServiceBFeignConfig",其中除了转发token外,还要添加X-Forwarded-*
headers对应的网关:
@Configuration
public class ServiceBFeignConfig {
@Autowired
private ApplicationProperties applicationProperties;
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
OAuth2AuthenticationDetails details =
(OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails();
requestTemplate.header("Authorization", "bearer " + details.getTokenValue());
if (applicationProperties.getFeign().getGatewayEnabled()) {
requestTemplate.header("X-Forwarded-Host", applicationProperties.getFeign().getGatewayHost());
requestTemplate.header("X-Forwarded-Port", applicationProperties.getFeign().getGatewayPort());
requestTemplate.header("X-Forwarded-Proto", applicationProperties.getFeign().getGatewayProtocol());
requestTemplate.header("X-Forwarded-Prefix", applicationProperties.getFeign().getServiceBPrefix());
}
}
};
}
}
您可以看到网关主机和端口已在属性文件中配置(在我的例子中由 Spring Cloud Config
提供)。 service-b 前缀也在这些文件中设置。
只有在属性文件中设置了 "gatewayEnabled" 属性 时才会添加这些 headers。
- 你必须从Spring Boot的组件扫描中忽略这个配置,即使它需要
@Configuration
注释,所以把它放在一个"ignorescan"包中,并在你的main Spring boot class, use:
@ComponentScan(basePackages = { "com.myservice" }, excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.myservice.ignorescan.*"))
最后,如果您将 gatewayEnabled 设置为 true,将添加转发 headers,并且对网关的 API 调用会获得正确的 HATEOAS 链接。
上下文
我的micro-services应用是基于spring-cloud
:前面配置了一个zuul
网关micro-services:service-a 和 service-b.
我的一个 API 要求 service-a 请求 service-b;我为此使用 feign
。
Zuul 将 X-FORWARDED-*
headers 发送到服务,以便他们正确重写 HATEOAS 链接(当服务配置为 ForwardedHeaderFilter
时)。
我的问题是服务使用 Feign
相互通信,这依赖于 Hystrix
。
Hystrix
为每个请求创建一个新线程(我们不使用 SEMAPHORE 配置),因此 Spring 的 RequestContextHolder
中的请求在来自 [=59= 的 Feign 请求中丢失了]service-a 到 service-b,我不能再用 feign
拦截器丰富 feign
请求,因为原始请求丢失。
一些潜在的解决方案
Spring 现在直接支持使用参数 hystrix.shareSecurityContext: true
没有任何 "out of the box" 配置让 Hystrix 在线程之间共享请求。
一个解决方案可能是 implement my own HystrixConcurrencyStrategy
,它是 netflix.hystrix 的 class。
我最近的发现是这个 Pull Request 已经发送到 spring-cloud-netflix,但不幸的是没有集成。
我可以尝试复制Pull request的代码,然后创建一个bean,就像"eacdy"写的那样:
@Bean
public RequestAttributeHystrixConcurrencyStrategy hystrixRequestAutoConfiguration() {
return new RequestAttributeHystrixConcurrencyStrategy();
}
是否有更简单的解决方案来将 headers 从 Zuul
转发到 Hystrix
?
我想在使用相互通信的 Zuul
、Hystrix
和 HATEOAS
micro-services 时,我尝试做的是非常标准的,所以也许有些东西已经存在(但我找不到)?
谢谢!
我认为这是很常见的事情,但经过大量研究后,我找不到一种方法来自动转发 X-FORWARDED-*
headers 和 Feign
和 Hystrix
.
因此,我寻找了另一种有效且非常干净的解决方案:
- 在从service-a到service-b的
Feign
客户端中,我声明了一个特定的配置"ServiceBFeignConfig",其中除了转发token外,还要添加X-Forwarded-*
headers对应的网关:
@Configuration
public class ServiceBFeignConfig {
@Autowired
private ApplicationProperties applicationProperties;
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
OAuth2AuthenticationDetails details =
(OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails();
requestTemplate.header("Authorization", "bearer " + details.getTokenValue());
if (applicationProperties.getFeign().getGatewayEnabled()) {
requestTemplate.header("X-Forwarded-Host", applicationProperties.getFeign().getGatewayHost());
requestTemplate.header("X-Forwarded-Port", applicationProperties.getFeign().getGatewayPort());
requestTemplate.header("X-Forwarded-Proto", applicationProperties.getFeign().getGatewayProtocol());
requestTemplate.header("X-Forwarded-Prefix", applicationProperties.getFeign().getServiceBPrefix());
}
}
};
}
}
您可以看到网关主机和端口已在属性文件中配置(在我的例子中由 Spring Cloud Config
提供)。 service-b 前缀也在这些文件中设置。
只有在属性文件中设置了 "gatewayEnabled" 属性 时才会添加这些 headers。
- 你必须从Spring Boot的组件扫描中忽略这个配置,即使它需要
@Configuration
注释,所以把它放在一个"ignorescan"包中,并在你的main Spring boot class, use:
@ComponentScan(basePackages = { "com.myservice" }, excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.myservice.ignorescan.*"))
最后,如果您将 gatewayEnabled 设置为 true,将添加转发 headers,并且对网关的 API 调用会获得正确的 HATEOAS 链接。