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

在使用Feign进行远程调用时,当前服务是能拿到请求头信息的,请求头包含有登录认证Cookie等重要信息,但是在调用远程服务时,远程服务却拿不到请求头信息,因为使用Feign进行远程调用实际上是发起新的Request请求了,所以就获取不到上一个请求的数据。请求示意图如下所示:

此时我们需要在在当前服务中添加配置类,用于将当前请求信息传递给远程服务,下面是配置类示例代码:

java 复制代码
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author: 
 * @Desc:
 * @create:
 **/
@Configuration
public class GuliFeignConfig {
    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor(){
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                //RequestContextHolder是feign设计用于获取请求上下文数据的工具类
               ServletRequestAttributes requestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = requestAttributes.getRequest();
                if(request!=null){
                    //获取源请求的请求头数据
                    String cookie = request.getHeader("Cookie");
                    //给新请求同步源请求的Cookie
                    template.header("Cookie",cookie);
                }

            }
        };
    }
}

添加上面的配置类后,在同步环境中能可确保远程服务能获取当前服务的请求头数据。但是如果使用异步操作,仅靠上面的配置类是不够的。这是因为:

数据是线程私有的,不能共享,所以使用异步的远程服务获取不了主线程的请求数据。此时需要进行配置:

方法1:硬编码,在主线程中获取到请求数据,在异步线程操作中赋值进去,

优点:简单易懂,上手快;

缺点:侵入业务代码,且每使用一个线程就要写这样一段代码,还会导致大量冗余代码。

示例代码:

java 复制代码
         //获取当前线程请求数据
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //使用异步编排处理多个远程请求任务
        //1.远程查询会员的收货地址
        CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
            //使用异步编排后,由于线程不同,需要将源请求上下文数据赋给当前线程
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressVo> address = orderFeignServie.getAddress(memberRespVo.getId());
            orderConfirmVo.setAddress(address);
        }, executor);

        //2.远程查询购物车中的购物项
        CompletableFuture<Void> getCartItemFuture = CompletableFuture.runAsync(() -> {
            //使用异步编排后,由于线程不同,需要将请求源上下文数据赋给当前线程
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVo> orderItemVos = cartFeignService.currentUserCartItem();
            orderConfirmVo.setItems(orderItemVos);
        }, executor);

方法2: 创建一个抽象类,实现Runnable方法。

优点:无侵入,代码简洁;

下面是示例代码:

java 复制代码
public abstract class MyRunnable implements Runnable{
    private RequestAttributes requestAttributes;

    public MyRunnable() {
        requestAttributes = RequestContextHolder.getRequestAttributes();
    }

    public abstract void myRun();

    @Override
    public void run() {
        //每一个线程都来共享之前的请求数据
        RequestContextHolder.setRequestAttributes(requestAttributes);
        myRun();
    }
}

然后在业务代码中使用MyRunnable的myRun()方法:

java 复制代码
//开启第一个异步任务
CompletableFuture<Void> addressFuture2 = CompletableFuture.runAsync(new MyRunnable() {
	@Override
	public void myRun() {
		//1、远程查询所有的收获地址列表
		List<MemberAddressVo> address = memberFeignService.getAddress(memberResponseVo.getId());
		confirmVo.setMemberAddressVos(address);
	}
}, threadPoolExecutor);

如此便可在异步使用Feign进行远程调用时获取到当前请求的请求数据。

更多信息可参考:谷粒商城实战笔记-问题记录-Feign异步调用丢失请求头问题_异步调用feign请求对象丢失-CSDN博客

相关推荐
KeyAction666615 小时前
从西班牙高铁追尾看安全系统设计:当违规指令成为输入,防护逻辑如何兜底
运维·服务器·安全
夜雪一千15 小时前
Linux 管道、重定向命令介绍
linux·运维·chrome
江华森15 小时前
数据中心网络技术基础 —— 从原理到实操
linux·运维
网络小江16 小时前
组网第41课:ACL 门禁——标准/扩展、规则顺序、time-range、in/out 方向
运维·网络安全·acl·访问列表·in/out
牛马工作号16 小时前
Copyparty 轻量文件共享:Docker Compose 部署、权限与多协议使用全指南
运维·docker·容器
骑着蜗牛撵大象32716 小时前
手写一个 HTTP 服务器:从 socket 到 epoll,Linux 上到底怎么把请求变成响应
linux·服务器·网络·http·epoll·socket编程·并发模型
星恒随风17 小时前
Linux Socket TCP编程(二):逐文件重构多进程、多线程与线程池服务器,深入fork、pthread_create、popen和std::bind
linux·服务器·笔记·学习·tcp/ip
晚风叙码17 小时前
Linux 进程概念(下):程序地址空间与虚拟内存
linux·服务器·算法
无足鸟ICT17 小时前
【RHCA+】影响Linux系统性能的因素
linux·运维·服务器
论文复现现场17 小时前
DeepSeek V4.1 Flash 和 V4 Pro 有什么区别?API 价格、性能与迁移建议
java·服务器·人工智能·python·大模型api·deepseek·deepseek v4.1