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);
    }
}
相关推荐
whltaoin5 分钟前
【 手撕Java源码专栏 】Spirng篇之手撕SpringBean:(包含Bean扫描、注册、实例化、获取)
java·后端·spring·bean生命周期·手撕源码
2501_9411444243 分钟前
Python + C++ 异构微服务设计与优化
c++·python·微服务
拾忆,想起1 小时前
Dubbo分组(Group)使用指南:实现服务接口的多版本管理与环境隔离
分布式·微服务·性能优化·架构·dubbo
带刺的坐椅1 小时前
Solon 不依赖 Java EE 是其最有价值的设计!
java·spring·web·solon·javaee
拾忆,想起2 小时前
Dubbo动态配置实时生效全攻略:零停机实现配置热更新
分布式·微服务·性能优化·架构·dubbo
Qiuner2 小时前
Spring Boot 机制二:配置属性绑定 Binder 源码解析(ConfigurationProperties 全链路)
java·spring boot·后端·spring·binder
Y***h18710 小时前
第二章 Spring中的Bean
java·后端·spring
8***293111 小时前
解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务(Spring MVC Springboot)同时允许跨域
java·前端·spring
U***e6311 小时前
PHP在微服务中的Mezzio
微服务·云原生·架构
多多*11 小时前
Java复习 操作系统原理 计算机网络相关 2025年11月23日
java·开发语言·网络·算法·spring·microsoft·maven