專門做海外服裝購(gòu)的網(wǎng)站成都seo公司
在線程池中,子線程調(diào)用其他服務(wù),請(qǐng)求頭丟失,token為空的情況
看了很多篇文章的處理方法和在自己親測(cè)的情況下做出說(shuō)明:
第一種:
這種方式只支持在主線程情況下,能夠處理,在多線程情況下,一旦主線程結(jié)束,這里還是會(huì)為空
第二種
//請(qǐng)求屬性可繼承,線程共享
RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(),true);
這種經(jīng)測(cè)試后發(fā)現(xiàn),主線程直接啟動(dòng)子線程,且執(zhí)行完自己邏輯后便結(jié)束不需理會(huì)子線程結(jié)果的,請(qǐng)求偶爾成功, 偶爾失敗;
也就是,當(dāng)父線程比子線程執(zhí)行完慢時(shí),請(qǐng)求屬性還在,子線程請(qǐng)求成功;當(dāng)快時(shí),請(qǐng)求屬性隨著父線程結(jié)束而銷毀,子線程的請(qǐng)求屬性變?yōu)閚ull,請(qǐng)求失敗。
第三種
采用的處理方式為:ThreadLocal
新建一個(gè)ThreadLocal 工具類,在多線程請(qǐng)求前,獲取到需要的屬性值或者設(shè)置所有的屬性值放入工具類MAP種進(jìn)行存儲(chǔ),在子線程調(diào)用服務(wù)時(shí)通過(guò)監(jiān)聽處將需要的值取出,就可以解決了。實(shí)際如下:
public class ThreadLocalUtil {//使用InheritableThreadLocal,使得共享變量可被子線程繼承private static final InheritableThreadLocal<Map<String,String>> headerMap = new InheritableThreadLocal<Map<String, String>>(){@Overrideprotected Map<String, String> initialValue() {return new HashMap<>();}};public static Map<String,String> get(){return headerMap.get();}public static String get(String key) {return headerMap.get().get(key);}public static void set(String key, String value){headerMap.get().put(key,value);}
}
在線程執(zhí)行前加:
(1
Enumeration<String> headerNames = servletRequest.getHeaderNames();while (headerNames.hasMoreElements()){String name = headerNames.nextElement();if (Objects.equals(name,"feignheader")){ThreadLocalUtil.set(name,servletRequest.getHeader(name));}}
或者直接獲取token,在需要的地方再進(jìn)行賦值。
(2
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes srat = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = srat.getRequest();
ThreadLocalUtil.set("token", request.getHeader("authorization"));
修改監(jiān)聽處獲取請(qǐng)求頭信息賦值
(1
@Slf4j
@Configuration
public class FeignConfig implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// //當(dāng)主線程的請(qǐng)求執(zhí)行完畢后,Servlet會(huì)被銷毀,因此在這里需要做判空
// if (attributes != null) {
// HttpServletRequest request = attributes.getRequest();
//
// Enumeration<String> headerNames = request.getHeaderNames();
//
// while (headerNames.hasMoreElements()) {
// String name = headerNames.nextElement();
// //不能把所有消息頭都傳遞下去,否則會(huì)引起其他異常;header的name都是小寫
// if (name.equals("feignheader")) {
// requestTemplate.header(name,request.getHeader(name));
// }
// }
// }//讀取設(shè)置的header信息,傳遞到下一個(gè)服務(wù)Map<String, String> headerMap = ThreadLocalUtil.get();for (String key : headerMap.keySet()) {log.info("--從ThreadLocal獲取消息頭傳遞到下一個(gè)服務(wù):key-[{}],value-[{}]",key,headerMap.get(key));requestTemplate.header(key,headerMap.get(key));}}
}
(2
這里之所以直接拿token,是因?yàn)楹竺鎮(zhèn)鬟f獲取token,未獲取到的問(wèn)題,如果有其它信息丟失,可用上面(1 的方法,會(huì)更全面一點(diǎn)
@Slf4j
@Configuration
public class FeignConfig implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();String token = null;//當(dāng)主線程的請(qǐng)求執(zhí)行完畢后,Servlet會(huì)被銷毀,因此在這里需要做判空if (attributes != null) {ServletRequestAttributes srat = (ServletRequestAttributes) requestAttributes;HttpServletRequest request = srat.getRequest();token = request.getHeader("authorization");}token = StringUtils.isNotBlank(token) ? token : ThreadLocalUtil.get("token");//將token傳遞出去requestTemplate.header("authorization", token);}
}