业务场景
通常微服务对于用户认证信息解析有两种方案
- 在 gateway 就解析用户的 token 然后路由的时候把 userId 等相关信息添加到 header 中传递下去。
- 在 gateway 直接把 token 传递下去,每个子微服务器自己在过滤器解析 token
现在有一个从 A 服务调用 B 服务接口的内部调用业务场景,无论是哪种方案我们都需要把 header 从 A 服务传递到 B 服务。
RequestInterceptor
OpenFeign 给我们提供了一个请求拦截器 RequestInterceptor ,我们可以实现这个接口重写 apply 方法将当前请求的 header 添加到请求中去,传递给下游服务, RequestContextHolder 可以获得当前线程绑定的 Request 对象
/** Feign 调用的时候传token到下游 */
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 从header获取X-token
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attr = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = attr.getRequest();
String token = request.getHeader("x-auth-token");//网关传过来的 token
if (StringUtils.hasText(token)) {
template.header("X-AUTH-TOKEN", token);
}
}
}
复制代码
然后在 @FeignClient 中使用
@FeignClient(
...
configuration = {FeignClientDecoderConfiguration.class, FeignRequestInterceptor.class})
public interface AuthCenterClient {
复制代码
多线程环境下传递 header(一)
上面是单线程的情况,假如我们在当前线程中又开启了子线程去进行 Feign 调用,那么是无法从 RequestContextHolder 获取到 header 的,原因很简单,看下 RequestContextHolder 源码就知道了,它里面是一个 ThreadLocal ,线程都变了,那肯定获取不到主线程请求里面的 requestAttribute 了。
原因已经清楚了,现在想办法去解决它。观察
RequestContextHolder.getRequestAttributes() 方法源码
public static RequestAttributes getRequestAttributes() {
RequestAttributes a