前言
最近一直在梳理之前做过的项目,想到之前遇到过的一个问题,场景是这样的,在我提交订单时,需要查询用户的地址信息和购物车被勾选的购物项,这样的话,我需要调用两个服务,一个是会员服务,一个是购物车服务。由于用户登陆信息是在整个系统共享的(这里采用分布式session解决),所以我在提交订单的时,调用购物车服务的时候,购物车服务的拦截器会拦截请求,判断用户是否登录。这时候请求头丢失,导致购物车服务拦截器返回用户未登录,但实际上是已经登录过的。还有一个问题是异步调用的时候,老请求线程不共享的问题,导致我业务中获取不到老请求报空指针异常的问题
远程调用出现的问题及解决方案
在分布式项目中,发送请求大致就两种,一种是浏览器访问,第二种是服务与服务之间通过OpenFeign远程调用。浏览器发送请求时,它会带上请求头的信息的,所以不会导致cookie丢失,这样用户真实登录的情况下不会判断未登录的异常情况。深入源码发现,Feign会重新创建一个request,这个请求是没有任何请求头的,这个请求模板会遍历请求拦截器的apply方法来丰富这个请求模板

看到这个地方就有办法解决了,解决方案就是,我写了一个feign拦截器,这里面注入了一个RequestInterceptor的对象,它是一个接口,我重写了它的apply方法,在里面拿到老请求中的请求头信息,放到这个新的请求模板里,我这里更新的是cookie。来看下代码:
@Configuration
public class GuliFeignConfig {
@Bean("requestInterceptor")
public RequestInterceptor requestInterceptor() {
RequestInterceptor requestInterceptor = 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)
//把老请求的cookie值放到新请求上来,进行一个同步
String cookie = request.getHeader("Cookie");
template.header("Cookie", cookie);
}

本文探讨了分布式系统中远程调用与异步调用出现的问题,包括请求头丢失和线程数据共享问题,提供了具体的解决方案,如使用Feign拦截器同步请求头和利用RequestContextHolder共享线程数据。
最低0.47元/天 解锁文章

656





