spring cloud微服务中多线程下,子线程通过feign调用其它服务,请求头token等丢失

在线程池中,子线程调用其他服务,请求头丢失,token为空的情况

看了很多篇文章的处理方法和在自己亲测的情况下做出说明:

第一种:

这种方式只支持在主线程情况下,能够处理,在多线程情况下,一旦主线程结束,这里还是会为空

第二种

css 复制代码
//请求属性可继承,线程共享
RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(),true);

这种经测试后发现,主线程直接启动子线程,且执行完自己逻辑后便结束不需理会子线程结果的,请求偶尔成功, 偶尔失败;

也就是,当父线程比子线程执行完慢时,请求属性还在,子线程请求成功;当快时,请求属性随着父线程结束而销毁,子线程的请求属性变为null,请求失败。

第三种

采用的处理方式为:ThreadLocal

新建一个ThreadLocal 工具类,在多线程请求前,获取到需要的属性值或者设置所有的属性值放入工具类MAP种进行存储,在子线程调用服务时通过监听处将需要的值取出,就可以解决了。实际如下:

css 复制代码
public class ThreadLocalUtil {

    //使用InheritableThreadLocal,使得共享变量可被子线程继承
    private static final InheritableThreadLocal<Map<String,String>> headerMap = new InheritableThreadLocal<Map<String, String>>(){
        @Override
        protected 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);
    }
}

在线程执行前加:

(1

css 复制代码
		Enumeration<String> headerNames = servletRequest.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            if (Objects.equals(name,"feignheader")){
                ThreadLocalUtil.set(name,servletRequest.getHeader(name));
            }
        }

或者直接获取token,在需要的地方再进行赋值。

(2

css 复制代码
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes srat = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = srat.getRequest();
ThreadLocalUtil.set("token", request.getHeader("authorization"));

修改监听处获取请求头信息赋值

(1

css 复制代码
@Slf4j
@Configuration
public class FeignConfig implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
//        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        //当主线程的请求执行完毕后,Servlet会被销毁,因此在这里需要做判空
//        if (attributes != null) {
//            HttpServletRequest request = attributes.getRequest();
//
//            Enumeration<String> headerNames = request.getHeaderNames();
//
//            while (headerNames.hasMoreElements()) {
//                String name = headerNames.nextElement();
//                //不能把所有消息头都传递下去,否则会引起其他异常;header的name都是小写
//                if (name.equals("feignheader")) {
//                    requestTemplate.header(name,request.getHeader(name));
//                }
//            }
//        }

        //读取设置的header信息,传递到下一个服务
        Map<String, String> headerMap = ThreadLocalUtil.get();
        for (String key : headerMap.keySet()) {
            log.info("--从ThreadLocal获取消息头传递到下一个服务:key-[{}],value-[{}]",key,headerMap.get(key));

            requestTemplate.header(key,headerMap.get(key));
        }

    }
}

(2

这里之所以直接拿token,是因为后面传递获取token,未获取到的问题,如果有其它信息丢失,可用上面(1 的方法,会更全面一点

css 复制代码
@Slf4j
@Configuration
public class FeignConfig implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String token = null;
        //当主线程的请求执行完毕后,Servlet会被销毁,因此在这里需要做判空
        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);
    }
}
相关推荐
萧瑟余晖5 小时前
Java深入解析篇十七之Spring Security
java·开发语言·spring
Flittly11 小时前
【雕虫大技】Agent 动态 Skill 供应链安全加固(二):执行隔离沙箱实战
java·spring boot·spring
星期一研究室17 小时前
代码块:长文中的‘荧光浮标’!让「关键内容」无损高亮呈现
微服务·产品·设计
BUG指挥官1 天前
Sa-Token和Spring Security对比
java·后端·spring
geminigoth1 天前
Spring AI Alibaba 入门开发一(备份)
java·人工智能·spring
xbgRS1 天前
spring整合mybaits
java·spring·mybatis
ruleslol1 天前
静态依赖注入 VS 动态依赖查询
spring
墨雨晨曦882 天前
Spring AI总结
java·人工智能·spring
用户3126874877202 天前
Spring Boot 异常处理到底怎么玩的?从 DispatcherServlet 到全局兜底的全链路拆解
spring
星期一研究室2 天前
从“能看”到“爱看”:用色彩心理学打造人人爱看的的专业文档🧩
微服务·产品·设计