Spring WebFlux中ThreadLocal实现及跨微服务Header传递咨询
Spring WebFlux 跨微服务Header自动传递实现方案
首先要明确:Spring WebFlux 是响应式编程模型,ThreadLocal并不适用——因为响应式流会在线程池之间切换,ThreadLocal的上下文会丢失。正确的做法是使用Reactor提供的Context来存储和传递Header信息。
实现步骤
1. 定义Header常量和上下文Key
先统一要传递的Header名称,比如X-Request-Id,同时定义Reactor Context的Key:
public class HeaderConstants { public static final String REQUEST_ID_HEADER = "X-Request-Id"; public static final ContextKey<String> REQUEST_ID_CONTEXT_KEY = ContextKey.create("requestId"); }
2. 编写WebFilter拦截入站请求,将Header存入Reactor Context
这个Filter会在每个请求进来时,提取指定Header,存入当前Reactor的Context中:
@Component public class RequestIdFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { String requestId = exchange.getRequest().getHeaders().getFirst(HeaderConstants.REQUEST_ID_HEADER); // 如果Header不存在,生成一个默认值(可选) if (requestId == null) { requestId = UUID.randomUUID().toString(); } // 将requestId存入Reactor Context return chain.filter(exchange) .contextWrite(context -> context.put(HeaderConstants.REQUEST_ID_CONTEXT_KEY, requestId)); } }
3. 自定义WebClient过滤器,从Context中获取Header并添加到出站请求
编写一个ExchangeFilterFunction,在WebClient发送请求前,从当前Reactor Context中取出Header,添加到请求头里:
@Component public class RequestIdExchangeFilter { public ExchangeFilterFunction addRequestIdHeader() { return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { // 从Context中获取requestId return Mono.deferContextual(contextView -> { String requestId = contextView.getOrDefault(HeaderConstants.REQUEST_ID_CONTEXT_KEY, ""); if (!requestId.isEmpty()) { // 构建新的请求,添加Header ClientRequest modifiedRequest = ClientRequest.from(clientRequest) .header(HeaderConstants.REQUEST_ID_HEADER, requestId) .build(); return Mono.just(modifiedRequest); } return Mono.just(clientRequest); }); }); } }
4. 配置WebClient,注入自定义过滤器
创建WebClient Bean时,把上面的过滤器添加进去,这样所有通过这个WebClient发送的请求都会自动携带Header:
@Configuration public class WebClientConfig { @Autowired private RequestIdExchangeFilter requestIdExchangeFilter; @Bean public WebClient webClient() { return WebClient.builder() .filter(requestIdExchangeFilter.addRequestIdHeader()) .build(); } }
5. 业务中使用WebClient调用其他微服务
在Service层注入WebClient直接使用即可,无需手动处理Header:
@Service public class DemoService { @Autowired private WebClient webClient; public Mono<String> callOtherService() { return webClient.get() .uri("http://other-service/api/demo") .retrieve() .bodyToMono(String.class); } }
关键说明
- 为什么不用ThreadLocal?:Reactor的线程模型是异步非阻塞的,一个请求的处理会在多个线程间切换,ThreadLocal的上下文无法跨线程传递,会导致Header丢失。
- Reactor Context的作用:Context是绑定在Mono/Flux流上的,会跟随流的整个生命周期,无论线程如何切换,都能正确获取到存储的信息。
内容的提问来源于stack exchange,提问作者bharathi
相关产品推荐
相关产品推荐

