如何在Controller中访问Reactor Context?WebFilter填充场景解析
在WebFilter中设置Reactor Context后,如何在Controller中访问
你的核心误解在于对Reactor Context传递方向和Spring WebFlux请求链的结合逻辑理解有误,下面详细解释并给出实现方案:
1. Reactor Context的核心传递规则
Reactor Context是绑定在订阅关系上的,传递方向是从订阅者(下游)向上游传递。当你调用contextWrite修改Context时,所有位于这个操作上游的Reactor操作,都能访问到修改后的Context。
2. Spring WebFlux请求链中的Context传递逻辑
在WebFilter中,chain.filter(exchange)代表的是后续的请求处理链(包含Controller的业务逻辑)。如果你对chain.filter(exchange)返回的Mono调用contextWrite,相当于给整个后续处理链的订阅路径注入了Context——当Controller中的Mono/Flux被订阅时,订阅请求会向上传递,经过这个Context修改步骤,最终Controller能拿到对应的Context值。
3. 代码实现示例
WebFilter中设置Context
@Component public class ContextInjectFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { // 给后续的Controller处理链注入Context return chain.filter(exchange) .contextWrite(ctx -> ctx.put("REQUEST_TRACE_ID", "abc-123-xyz")); } }
Controller中访问Context
@RestController @RequestMapping("/demo") public class ContextAccessController { @GetMapping("/trace") public Mono<String> getTraceId() { // 使用deferContextual延迟获取Context(必须在订阅阶段执行) return Mono.deferContextual(contextView -> { String traceId = contextView.get("REQUEST_TRACE_ID"); return Mono.just("当前请求Trace ID:" + traceId); }); } }
4. 关键注意事项
- 必须使用
deferContextual或transformDeferredContextual来访问Context:Context是在订阅阶段才确定的,这两个方法会延迟到订阅时执行逻辑,确保能拿到正确的Context。 - 不要在WebFilter的前置逻辑流上调用
contextWrite:比如如果写Mono.just(exchange).contextWrite(...).then(chain.filter(exchange)),这样设置的Context不会传递到Controller,因为chain.filter(exchange)是独立的流。
参考文档
- Spring WebFlux官方文档:关于Reactor Context在Web请求处理中的集成说明,解释了Filter与Controller之间的Context传递机制。
- Reactor官方文档:详细说明Context的传递规则、
contextWrite和deferContextual的用法与适用场景。
内容的提问来源于stack exchange,提问作者Stephen
相关产品推荐
相关产品推荐

