My micro-services application is based on spring-cloud
: a zuul
gateway is configured in front of two micro-services: service-a and service-b.
One of my API requires that service-a requests service-b; I use feign
for that.
Zuul send X-FORWARDED-*
headers to the services, for them to rewrite the HATEOAS links correctly (when the services are configured with ForwardedHeaderFilter
).
My problem is that the services communicate with each other using Feign
, which relies on Hystrix
.
Hystrix
creates a new thread for each request (we don't use the SEMAPHORE config), so the request in Spring's RequestContextHolder
is lost in the Feign request from service-a to service-b, I can't enrich the feign
request with an feign
interceptor anymore since the original request is lost.
Forwarding authorization token is now supported directly by Spring with the parameter hystrix.shareSecurityContext: true
There isn't any "out of the box" configuration to have Hystrix shares the request between threads.
A solution could be to implement my own HystrixConcurrencyStrategy
, which is a class from netflix.hystrix.
My latest find is this Pull Request that has been sent to spring-cloud-netflix, but unfortunately not integrated.
I can try to copy the code of the Pull request, and create a bean, just as what "eacdy" wrote:
@Bean
public RequestAttributeHystrixConcurrencyStrategy hystrixRequestAutoConfiguration() {
return new RequestAttributeHystrixConcurrencyStrategy();
}
Is there an easier solution to forward the headers from Zuul
with Hystrix
?
I suppose that what I am trying to do is very standard when using Zuul
, Hystrix
, and HATEOAS
micro-services that communicate with each other, so maybe there is something that exists already (and that I couldn't find)?
Thanks !
I thought it was quite a common thing to achieve, but after a lot of research, I couldn't find a way to forward the X-FORWARDED-*
headers automatically with Feign
and Hystrix
.
So, I looked for another solution, which works and is quite clean:
Feign
client from service-a to service-b, I declared a specific configuration "ServiceBFeignConfig", which, in addition to forward the token, also add the X-Forwarded-*
headers corresponding to the gateway:@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());
}
}
};
}
}
You can see that the gateway host and port is configured in the properties files (that is served by Spring Cloud Config
in my case). The service-b prefix is also set in these files.
These headers are only added if the "gatewayEnabled" property is set in the properties files.
@Configuration
annotation, so put it in a "ignorescan" package, and on your main Spring boot class, use:@ComponentScan(basePackages = { "com.myservice" }, excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.myservice.ignorescan.*"))
At the end, the Forward headers will be added if you have the gatewayEnabled set to true, and the API call to the gateway get the correct HATEOAS links.