一.Feign远程调用丢失请求头问题
Feign在远程调用时,会重新包装请求(请求路径,请求参数)但是不会携带请求头,所以在到达被调服务时没有请求头信息
解决方法:
在Feign重新包装请求时,使用 RequestInterceptor 拦截器,把老请求中请求头重新保存到新的请求中
@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异步调用丢失请求头问题
解决方法:
把线程-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;
}