SpringCloud学习 - Feign远程调用丢失请求头问题的解决 使用Feign+CompletableFuture 异步调用丢失请求头的问题

SpringCloud学习 Feign远程调用 异步调用CompletableFuture 丢失请求头问题的解决

1.使用Feign进行远程调用丢失请求头问题

当使用Feign进行远程调用时,Feign会自动构造一个新的http请求再发送.因此会默认丢掉原请求的请求头信息.导致一些重要的数据丢失(Cookie)

在这里插入图片描述

解决方法: 添加Feign远程调用拦截器,在拦截器中进行请求头信息的同步.

原理:Feign在构造http远程调用请求时,会检查是否有添加拦截器RequestInterceptor(默认没有),如果有,在构造时会先执行拦截器的apply方法,因此在apply方法中实现请求头信息的同步可以解决原请求头信息丢失的问题.

在这里插入图片描述

设置拦截器:

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;
y
@Configuration
public class MyFeignConfigration {
    
    
    //设置feign发送请求的拦截器,解决feign远程调用请求头丢失的问题
    @Bean
    public RequestInterceptor requestInterceptor(){
    
    
        return new RequestInterceptor() {
    
    
            //设置以后,Feign在远程调用之前,会先执行apply方法
            @Override
            public void apply(RequestTemplate requestTemplate) {
    
    
                //1.使用RequestContextHolder获取在Controller层进入的请求的所有属性,底层是使用ThreadLocal的机制
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = attributes.getRequest();
                //2.同步请求头数据  (Cookie)
                String cookie = request.getHeader("Cookie");
                requestTemplate.header("Cookie",cookie);
            }
        };
    }
}

2. 使用Feign+CompletableFuture 异步调用丢失请求头的问题

场景:当使用Feign+CompletableFuture进行异步(多个线程之间)远程调用时,因为线程发送了改变.导致之前添加拦截器RequestInterceptor失效,(因为RequestContextHolder底层使用ThreadLocal进行同一线程的数据共享),而异步情况下线程改变,导致无法获取到原来的请求.

在这里插入图片描述

错误代码: 在CompletableFuture异步任务中进行Feign调用

CompletableFuture<Void> addrFuture = CompletableFuture.runAsync(() -> {
    
    
    //远程查询所有的收获地址
    List<MemberAddr> memberAddrs = memberFeignService.infoById(memberResVo.getId());
    confirmData.setAddress(memberAddrs);
}, executor);
CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
    
    
    //远程查询购物车所有选中的购物项
    List<OrderItemVo> userCartItems = cartFeignService.getUserCartItems();
    confirmData.setItems(userCartItems);
}, executor);

解决方法:使用RequestInterceptor进行拦截的前提下,在feign调用前手动添加请求信息

//获取原线程的请求参数
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();

CompletableFuture<Void> addrFuture = CompletableFuture.runAsync(() -> {
    
    
    //设置请求原线程下的参数
    RequestContextHolder.setRequestAttributes(attributes);
    //远程查询所有的收获地址
    List<MemberAddr> memberAddrs = memberFeignService.infoById(memberResVo.getId());
    confirmData.setAddress(memberAddrs);
}, executor);
CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
    
    
    //设置请求原线程下的参数
    RequestContextHolder.setRequestAttributes(attributes);
    //远程查询购物车所有选中的购物项
    List<OrderItemVo> userCartItems = cartFeignService.getUserCartItems();
    confirmData.setItems(userCartItems);
}, executor);
ignService.getUserCartItems();
    confirmData.setItems(userCartItems);
}, executor);

猜你喜欢

转载自blog.csdn.net/weixin_44634197/article/details/108619068