分布式组件-feign-常见问题

丢失请求头

feign远程调用如果不对之进行增强,则会丢失请求头。
Feign远程调用前,会通过遍历容器中的Feign包下的拦截器RequestInterceptor判断是否为当前的RequestTemplate进行增强。
远程调用核心代码


image.png

image.png

遍历private final List requestInterceptors;


image.png

如果Spring容器中没有装配的RequestInterceptor的bean实例,则默认使用一个不增强的RequestTemplate,其header中没有需要的请求头。
image.png

解决方案

装配一个RequestInterceptor 的bean实例,对RequestTemplate进行增强。

@Configuration
public class GuliFeignConfig {
    @Bean
    public RequestInterceptor requestInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                //1. 使用RequestContextHolder拿到老请求的请求数据
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                if (requestAttributes != null) {
                    HttpServletRequest request = requestAttributes.getRequest();
                    if (request != null) {
                        //2. 将老请求得到cookie信息放到feign请求上
                        String cookie = request.getHeader("Cookie");
                        template.header("Cookie", cookie);
                    }
                }
            }
        };
    }
}
image.png

异步线程丢失上下文

异步调用的时候,第十一行会报空指针

@Configuration
public class GuliFeignConfig {
    @Bean
    public RequestInterceptor requestInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                //1. 使用RequestContextHolder拿到老请求的请求数据
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                if (requestAttributes != null) {
                    HttpServletRequest request = requestAttributes.getRequest();
                    if (request != null) {
                        //2. 将老请求得到cookie信息放到feign请求上
                        String cookie = request.getHeader("Cookie");
                        template.header("Cookie", cookie);
                    }
                }
            }
        };
    }
}

因为异步调用会创建新线程,无法获取主线程的数据。
解决办法
利用RequestContextHolder通过ThreadLocal共享数据的特性,先在主线程中获取主线程的RequestAttributes,后在子线程中RequestContextHolder.setRequestAttributes(requestAttributes);


image.png
    @Override
    public ResponseResult confirmOrder() {
      
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
      
        CompletableFuture objectFuture = CompletableFuture.supplyAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //xxxx
            return Object;
        }, executor);
      }
  
}
 

                            
                        
                    
                    
                    

你可能感兴趣的:(分布式组件-feign-常见问题)