• 首页

  • 归档

  • 标签

  • 分类

  • 友链
M S B l o g
M S B l o g

ms

获取中...

07
21
java
总结
问题
spring cloud

feign远程调用及异步调用丢失请求头问题

发表于 2021-07-21 • java 问题 微服务 Feign 多线程 • 被 4,526 人看爆

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

Feign在远程调用时,会重新包装请求(请求路径,请求参数)但是不会携带请求头,所以在到达被调服务时没有请求头信息

image.png

解决方法:

在Feign重新包装请求时,使用 RequestInterceptor 拦截器,把老请求中请求头重新保存到新的请求中

image.png

@Configuration
public class GuliFeignConfig {

    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor(){
        return new RequestInterceptor(){

            @Override
            public void apply(RequestTemplate requestTemplate) {
                //1,RequestContextHolder拿到刚进来的请求
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = requestAttributes.getRequest();//老请求
                //同步请求头数据,cookie
                String cookie = request.getHeader("Cookie");
                //给新请求同步了老请求的cookie
                requestTemplate.header("Cookie",cookie);
            }
        };
    }
}

总结:

  • feign远程调用,自己创建一个新的request对象,按照指定的路径和参数发起新的请求,并得到响应结果。但是这个新的request对象请求头为空,所以丢失了原先请求中的数据。
  • feign在创建新的request对象时,会调用一系列容器中的RequestInterceptor对象,执行其apply方法,对这个创建好的request进行增强,再去真正执行请求。但是默认情况下容器中不存在这类拦截器对象。
  • 我们可以自己向容器中注册一个RequestInterceptor,在其apply方法体内,获取到原始request,将其数据取出,赋值到新的request中,完成请求头的同步。
    的request进行增强,再去真正执行请求。但是默认情况下容器中不存在这类拦截器对象。
  • 我们可以自己向容器中注册一个RequestInterceptor,在其apply方法体内,获取到原始request,将其数据取出,赋值到新的request中,完成请求头的同步。
  • RequestContextHolder借助ThreadLocal将每一个原始请求与tomcat为其分配的线程绑定,之后,只要在同个线程内,随时随地都可轻易获取到原始request。

二.Feign异步调用丢失请求头问题

image.png

解决方法:

把线程-1中的上下文内容拷贝到 线程-2 、 线程-3

@Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
            // 把主线程中的属性共享给其他线程
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //1,远程查询所有的收货地址列表
            List<MemberAddressVo> address = memberFeignService.getAddress(memberRespVo.getId());
            orderConfirmVo.setAddress(address);
        }, executor);

        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            // 把主线程中的属性共享给其他线程
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //2.远程查询购物车所有选中的购物项
            List<OrderItemVo> items = cartFeignService.getCurrentUserItems();
            orderConfirmVo.setItems(items);
        }, executor);


        //3.查询用户积分
        Integer integration = memberRespVo.getIntegration();
        orderConfirmVo.setIntegration(integration);

        CompletableFuture.allOf(getAddressFuture,cartFuture).get();

        return orderConfirmVo;
    }
分享到:
防止重复提交,接口幂等性
过滤器与拦截器的使用及区别
  • 文章目录
  • 站点概览
ms

MSms

⚓️HelloWorld⚓️

QQ Email RSS
看爆 Top5
  • MyBatis-Plus分页查询 5,937次看爆
  • @Autowired与@Resource的区别 4,755次看爆
  • feign远程调用及异步调用丢失请求头问题 4,527次看爆
  • spring cloud中OpenFeign整合Sentinel启动报错 4,424次看爆
  • Certbot查看证书过期时间,手动续期以及自动续期 3,302次看爆

Copyright © 2025 ms · 湘ICP备20015239号

Proudly published with Halo · Theme by fyang · 站点地图