问题
在写项目的过程中,使用OpenFeign进行远程调用服务时,获取不到原请求头中携带的cookie信息,也就是Feign远程调用丢失请求头问题。
http://order.gulimall.com/toTrade:
public OrderConfirmVo getConfirmOrder() {
OrderConfirmVo vo = new OrderConfirmVo();
// 远程调用 获取被选中的购物车中的购物项项信息
List<OrderItemVo> orderItemVo = cartFeignService.getCheckedItem();
vo.setItems(orderItemVo);
return vo;
}
远程调用接口:
@FeignClient("gulimall-cart")
public interface CartFeignService {
@PostMapping("/checkedItem")
List<OrderItemVo> getCheckedItem();
}
被调用方法:
@PostMapping("/checkedItem")
public List<CartItemVo> getCheckedItem() {
String cookie = request.getHeader("Cookie");
log.info("接收到携带Cookie: {}", cookie);
return cartService.getCheckedItem();
}
问题:
- 发送请求,http://order.gulimall.com/toTrade,并且携带请求头
Cookie=GULISESSION=ZWE2OWI1YzMtYzQxNy00YTAwLWI1M2YtNGNhMzI1MDg2OTgw,执行目标方法getConfirmOrder()
; getConfirmOrder()
方法内部远程调用getCheckedItem()
;getCheckedItem()
,打印日志:接收到携带Cookie: null。
导致原因
在使用OpenFeign进行远程调用时,底层会给我们生成一个新的request请求去请求被调用的服务,并且这个请求不携带任何请求头,从而导致了在被调用方法中获取不到请求头cookie的问题。
如何解决
查看上述targetRequest
方法:
在远程调用方法之前,会执行很多的拦截器,我们可以利用这些拦截器来给OpenFeign生成的新的request请求包装一些其它参数,因此,我们只需要在容器配置一个RequestInterceptor
类型的拦截器,将原请求中携带的请求头Cookie封装到新的请求中即可。
创建配置类:
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate template) {
// 获取原请求
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// 原请求 也就是http://order.gulimall.com/toTrade
HttpServletRequest request = attributes.getRequest();
// 获取原请求中携带的Cookie请求头
String cookie = request.getHeader("Cookie");
// 将cookie 同步到新的请求的请求头中
template.header("Cookie", cookie);
}
};
}
}
注意:这里RequestContextHolder.getRequestAttributes()方法获取原请求信息,RequestContextHolder是基于本地线程线程作用域(TreadLocal)获取的,如果请求映射到的controller控制器方法和执行到这里使用的线程不同,这里是获取不到原请求的。
再次发送请求,打个断点,测试原请求中的Cookie是否能够同步到新生成请求的请求头中: