情景描述:
一个网关Gateway
,一个微服务A,
一个微服务B
;
- 网关服务中配置了路由规则:
- id: serviceA
uri: lb://A-service
predicates:
- Path=/A/**
- id: serviceB
uri: lb://B-service
predicates:
- Path=/B/**
当需要访问服务A
和服务B
,都会经过网关。
- 网关中有全局过滤器
Globalfilter
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String string = request.getPath().toString();
if(isExclude(string)){
return chain.filter(exchange);
}
String token=null;
List<String> authorlization = request.getHeaders().get("authorization");
if(authorlization!=null&&!authorlization.isEmpty()){
token = authorlization.get(0);
}
Long l=null;
try {
userID = jwtTool.parseToken(token);
Long finalid = userID;
ServerHttpRequest uid = request.mutate().headers(h -> {
h.add("uid", finalid.toString());
}).build();
exchange.mutate().request(uid).build();
} catch (Exception e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
return chain.filter(exchange);
}
网关过滤器往request
中加入了userId
;
之后的微服务可以通过自定义拦截器userInterceptor
获取这个userId
来用于各个业务;
private static final ThreadLocal<Long> tl = new ThreadLocal<>();
public class userInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String uid = request.getHeader("uid");
Long l = Long.valueOf(uid);
tl.set(l);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
tl.remove();
}
}
之后的微服务通过tl.get()获得userId;
这里都没有什么问题,
但当微服务A
通过OpenFeign
的FeignClient
调用微服务B
时,如果微服务B
某个业务需要用到userId
时,会发现通过ThreadLocal
中的用户id
是空的!!!
找了好久,发现是由于通过feign
调用另一个微服务时,它的线程可能是变了,好像叫feign熔断机制
。
通过关闭它,
feign:
hystrix:
enabled: false
这样调用另一个微服务时ThreadLocal
中的userId
就不为空了。
参考Feign调用服务Session失效问题以及使用RequestContextHolder.getRequestAttributes()获取值为null的问题 还有几种方法。