博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Feign 请求信息丢失

Posted on 2022-04-08 11:28  zachry-r  阅读(375)  评论(0)    收藏  举报

Feign 请求信息丢失

  • 邮箱:361400631@q q.com
  • 作者:Zarchary

1.问题出现场景

1.1 问题出现

​ 微服务之间调用,如果是通过登陆的 session 用户信息,发出远程调用请求,Cookie丢失

1.2 出现场景

微服务A,从微服务B获取信息。

  • 首先 请求A服务 /getInfo,请求头中带有登陆的 Cookie信息image-20220407170426710

  • 当 A服务通过 Feign远程调用 同样需要登陆才行获取资源信息的 服务B时,丢失了 Cookie信息,此时再调用 b服务没有携带 Cookie信息就会出现问题image-20220407165758078

  • Feign 源码查看

    • fegin代理方法 invoke, dispath的invoke调用

      image-20220407172101941

    • 查看 代理的 invoke源码

      1.先构建了一个 template模板

      2.executeAndDecode(),执行请求模板

      image-20220407173808211

    • targetRequest() 执行目标请求

      image-20220407174024390

    • 最后我们在看 这个 targetRequest()

      他从 RequestInterceptor的拦截器里拿出拦截器对 请求模版添加参数。默认情况下 是没有 RequestInterceptor这个拦截器的。现在的情况 服务A—> 服务B ,携带的 Cookie信息被 feign丢弃,如果想要解决,那么去往容器里添加一个 RequestInterceptor这个拦截器即可

      image-20220407174228970

      image-20220407174111671

2. 问题解决

2.1 为什么添加 RequestInterceptor

  • 首先看一下 feign 的工厂,需要传入一个 requestInterceptor 拦截器

    image-20220408091843356

  • 我们再看一下这个拦截器是哪里生成的。 feign的构造对象里面声明了一个空的requestInterceptor集合。那是在什么时候赋值的呢? 继续往下看

    image-20220408091955679

  • 这里就看到了,他是从容器里拿到的requestInterceptor。 所以我们只需要按照自己的需求,给容器添加 requestInterceptor,增强一下feign 的功能即可

    image-20220408092143437

2.2 注入一个requestInterceptor 的bean

2.3 增强前后对比

2.3.1 增强前

​ 可以看到 ,服务A发出feign远程调用, feign生成了一个新的请求, 请求头里是没有携带Cookie信息的

image-20220408094155884

2.3.2 增强后

​ 可以看到的是 Cookie被设置进去了

image-20220408094745597

3.异步线程编排再出问题

3.1 异步编排,上下文丢失

​ 从这个上下文管理可以看到,获取的请求是通过 ThreadLocal 线程共享的,此时异步编排下, 线程发生了改变,导致上下文信息丢失

image-20220408105015149

image-20220408103605790

3.2 问题解决

​ 在异步线程执行之前,获取主线程的请求信息requestAttributes

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

在每个异步线程里面设置 requestAttributes

CompletableFuture<Void> addressTask = CompletableFuture.runAsync(() -> {
    // 设置异步线程的请求属性
    RequestContextHolder.setRequestAttributes(requestAttributes);
    List<MemberReviceAddVo> address = memberFeignService.getAddress(memRespVo.getId());
    confirmVo.setAddress(address);
}, executor);

自此问题就解决了。 如果什么问题,请留言