Feign远程调用丢失请求头问题

Feign同步调用

  在分布式开发中,会用到Feign进行远程调用其他服务的接口获取数据,首先看看这个调用原理,如下图:
在这里插入图片描述
  通过Feign进行远程调用时,是Java模拟发送一个请求到另一个服务,但是这个请求不像浏览器要样会自己携带上当前域名下的cookie信息,这个Java模拟的请求是没有任何cookie信息的,所以在调用另一个服务时被拦截器拦截时认证不通过,因此调用失败。
  为了解决这个问题,我们可以使用Feign远程调用的拦截器,在Feign构造好请求后,先交于拦截器进行处理,其流程大致如下图:
在这里插入图片描述
  

@Configuration
public class FeignConfig {
    @Bean
    public RequestInterceptor requestInterceptor() {
        return new RequestInterceptor() {
            /**
             * 调用远程方法之前先调用此方法
             */
            @Override
            public void apply(RequestTemplate requestTemplate) {
                //Spring提供的工具,获取当前请求的属性,
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                //获取当前请求对象
                HttpServletRequest request = requestAttributes.getRequest();
                //同步请求头信息
                requestTemplate.header("Cookie", request.getHeader("Cookie"));
            }
        };
    }
}

  

Feign异步调用

  但是在Feign异步调用时使用上面的拦截器会失效,在拦截器中通过断点调试发现,它直接丢失了上下文对象,也就是拦截器中的HttpServletRequest为空,而在Feign拦截器中是通过RequestContextHolder去获取上下文信息的,而RequestContextHolder是通过ThreadLocal去获取的,也就是说在同步调用时,从前往后执行都是在同一个线程中,数据在同样一个线程是可以共享的,但是我们在异步调用时,可能是通过创建了一个新的线程去执行的,这个线程和主线程不是同一个线程,所以是获取不到主线程的上下文信息的。我们在执行业务逻辑时又不得不考虑多线程去执行来提高效率
在这里插入图片描述
  所以为了解决这个问题,我们可以在主方法中先获取请求的上下文信息,然后在执行子线程将主线程的上下文信息放在子线程的RequestContextHolder中,这样在子线程执行feign拦截器时就可以获取到上下文信息了

public void testDemo() throws ExecutionException, InterruptedException {
    // 主线程请求的上下文信息
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> {
        //设置上下文信息
        RequestContextHolder.setRequestAttributes(requestAttributes);
        //TODO 执行远程调用
    }, executor);
    CompletableFuture<Void> task2 = CompletableFuture.runAsync(() -> {
        //设置上下文信息
        RequestContextHolder.setRequestAttributes(requestAttributes);
        //TODO 执行远程调用
    }, executor);
    CompletableFuture.allOf(task1, task2).get();
}

// TODO feign的拦截器代码不用改
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

華小灼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值