那么如何解決請求頭的傳遞問題呢?
一 最容易想到的方法是在轉發和請求時主動將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
對象。