丢失请求头
feign远程调用如果不对之进行增强,则会丢失请求头。
Feign远程调用前,会通过遍历容器中的Feign包下的拦截器RequestInterceptor判断是否为当前的RequestTemplate进行增强。
远程调用核心代码
遍历private final List<RequestInterceptor> requestInterceptors;
如果Spring容器中没有装配的RequestInterceptor的bean实例,则默认使用一个不增强的RequestTemplate,其header中没有需要的请求头。
解决方案
装配一个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);
}
}
}
};
}
}
异步线程丢失上下文
异步调用的时候,第十一行会报空指针
@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);
@Override
public ResponseResult<OrderConfirm> confirmOrder() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
CompletableFuture<Object> objectFuture = CompletableFuture.supplyAsync(() -> {
RequestContextHolder.setRequestAttributes(requestAttributes);
//xxxx
return Object;
}, executor);
}
}