那么如何解决请求头的传递问题呢?
一 最容易想到的方法是在转发和请求时主动将header参数传入。
通过在controller中设置RequestHeader参数。这种方法的弊端是每次都得修改controller中的api方法,耦合性高,一旦需要增加header参数,则所有涉及到的controller方法都要调整一遍。
二 比较通用的方法是使用拦截器,在转发请求时,统一添加header信息。
@Component public class FeignClientsConfigurationCustom implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder .getRequestAttributes(); if (null != attributes) { HttpServletRequest request = attributes.getRequest(); if (null != request) { Enumeration<String> headerNames = request.getHeaderNames(); if (headerNames != null) { while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String values = request.getHeader(name); requestTemplate.header(name, values); } } } } } }
但是,如果开启了hystrix隔离策略,则会影响header参数的转发。
hystrix的默认隔离策略是线程隔离。
在这种情况下,转发调用和真正请求的不是同一个线程,因此没有办法获取到ThreadLocal中的数据。
此时,ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 拿到的attributes是null,因为这里用到了ThreadLocal。
因此在线程隔离策略下,服务端拿不到header信息。那么怎么办呢?
解决方案一:修改默认隔离策略为信号量模式
hystrix.command.default.execution.isolation.strategy=SEMAPHORE,这样的话转发线程和请求线程实际上是一个线程。但是这种方法有些弊端,hystrix官方不建议使用信号量模式。
解决方案二:自定义hystrix隔离策略
思路是将现有的并发策略作为新并发策略的成员变量。在新并发策略中,返回现有并发策略的线程池、Queue,将策略加到Spring容器即可。目前,Spring Cloud Sleuth以及Spring Security都通过该方式传递 ThreadLocal
对象。