Feign远程调用问题
1.Feign远程调用丢失请求头问题
以如下代码为例:
@FeignClient("gulimall-member")
public interface MemberFeignService {
@GetMapping("member/memberreceiveaddress/{memberId}/address")
List<MemberAddressVo> getAddress(@PathVariable("memberId") Long memberId);
}
F7断点进入ReflectiveFeign.java:
F7断点进入SynchronousMethodHandler.java:
F7断点进入executeAndDecode方法:
再进入targetRequest方法,发现RequestInterceptors是0个:
解决方案:如果我们只有注入了RequestInterceptor拦截器,我们就可以给容器中的RequestTemplate添加请求头信息了
代码:在容器中注入RequestInterceptor(feign的请求拦截器)
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return template -> {
//1、RequestContextHolder拿到刚进来的这个请求
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest(); //老请求
//同步请求头数据 Cookie
String cookie = request.getHeader("Cookie");
//给新请求同步了老请求的cookie
template.header("Cookie", cookie);
System.out.println("feign远程之前先进行RequestInterceptor.apply");
}
};
}
}
结论:
2.Feign远程调用异步情况丢失上下文问题
基于1.的feign请求拦截器配置
以如下确认订单代码为例:
OrderConfirmVo confirmVo = new OrderConfirmVo();
MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
System.out.println("主线程..." + Thread.currentThread().getId());
CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
System.out.println("member线程..." + Thread.currentThread().getId());
//1、远程查询所有的收获地址列表
List<MemberAddressVo> address = memberFeignService.getAddress(memberRespVo.getId());
confirmVo.setAddress(address);
}, executor);
CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
System.out.println("cart线程..." + Thread.currentThread().getId());
//2、远程查询购物车所有选中的购物项
List<OrderItemVo> items = cartFeignService.getCurrentUserCartItems();
confirmVo.setItems(items);
//feign在远程调用之前要构造请求,调用很多的拦截器
//RequestInterceptor interceptor: requestInterceptors
}, executor);
//3、查询用户积分
Integer integration = memberRespVo.getIntegration();
confirmVo.setIntegration(integration);
//4、其他数据自动计算
//TODO 5、防重令牌
CompletableFuture.allOf(getAddressFuture, cartFuture).get();
主线程运行:
两个feign异步线程与主线程不是同一线程,导致两个feign异步线程ThreadLocal中的请求头信息为空,从而出现异步线程丢失了上文的问题
解决方案:
在异步线程执行之前的主线程中获取之前的请求:
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
然后在异步线程中的feign调用之前,设置之前的请求数据
//每一个线程都来共享之前的请求数据
RequestContextHolder.setRequestAttributes(requestAttributes);
结论:
本文来自博客园,作者:冰枫丶,转载请注明原文链接:https://www.cnblogs.com/lqsblog/p/16908969.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)