当前位置: 首页 > news >正文

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

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

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

第一种:

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

第二种

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

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

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

第三种

采用的处理方式为:ThreadLocal

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

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);}
}

在线程执行前加:
(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,在需要的地方再进行赋值。
(2

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

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

(1

@Slf4j
@Configuration
public class FeignConfig implements RequestInterceptor {@Overridepublic 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 的方法,会更全面一点

@Slf4j
@Configuration
public class FeignConfig implements RequestInterceptor {@Overridepublic 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);}
}
http://www.lryc.cn/news/231782.html

相关文章:

  • Nacos 高级玩法:深入探讨分布式配置和服务发现
  • CCF CSP认证历年题目自练Day45
  • outlook群发邮件
  • 【Attack】针对GNN-based假新闻检测器
  • APIcloud 【现已更名 用友开发中心】 iOS发版 应用程序请求用户同意访问相机和照片,但没有在目的字符串中充分说明相机和照片的使用。
  • 记一次弱口令之后引发的获取服务器权限
  • AJAX入门Day01笔记
  • spring boot 环境变量问题
  • Javaweb开发 利用servlet+jsp+jdbc+tomcat数据库实现登录功能
  • flutter下拉列表
  • ElastaticSearch -- es深度分页 searchAfter
  • 【2021集创赛】Arm杯二等奖-基于Arm核的智慧病房手势识别方案
  • 通过注解统计接口调用耗时
  • Oracle-动态sql学习笔记,由易至难讲解七个例子
  • Kafka 的应用场景
  • 保驾“双十一” 博睿数据助力电商零售迎高峰无烦忧
  • F.binary_cross_entropy、nn.BCELoss、nn.BCEWithLogitsLoss与F.kl_div函数详细解读
  • 后端接口性能优化分析
  • 【ceph】ceph集群中使用多路径(Multipath)方法
  • Xshell+Xftp通过代理的方式访问局域网内网服务器
  • 对盒子中的材料进行计数
  • 科技驱动固定资产管理变革:RFID技术的前沿应用
  • Django路由层之有名分组和无名分组、反向解析、路由分发、伪静态的概念、名称空间、虚拟环境、Django1和Django2的区别
  • 【nlp】2.5 人名分类器实战项目(对比RNN、LSTM、GRU模型)
  • 海康Visionmaster-环境配置:MFC 二次开发环境配置方法
  • 利用EXCEL中的VBA对同一文件夹下的多个数据文件进行特定提取
  • FPGA时序约束(七)文献时序约束实验测试
  • 【数据库开发】DataX开发环境的安装部署(Python、Java)
  • Flutter实践一:package组织
  • SpringCloud微服务:Ribbon负载均衡