Spring WebFlux:Controller与Filter通过Context共享数据失败求助
问题原因分析
- Reactor Context的单向传递特性:Reactor Context是不可变对象,仅向下游订阅者传递。下游通过
subscriberContext/contextWrite新增的Context条目无法回溯到上游操作中。你在Filter中chain.filter(...)之后添加的subscriberContext,是给Controller执行完成后的后续操作设置Context,而非传递给Controller;Controller修改的Context是下游生成的新实例,上游Filter的beforeCommit回调无法获取。 - 无效的Context嵌套操作:你在Filter中执行
context.put("CONTEXT", context),本质是将当前Context的快照存入自身(Context不可变),后续Controller修改的是新的Context实例,和Filter中存储的快照无关,导致数据无法传递。
修正方案
利用可变容器在Context中传递数据——上游Filter将可变容器放入Context,下游Controller修改容器内的内容,上游即可读取到更新后的数据(容器是同一个对象,不受Context不可变特性影响)。
步骤1:定义可变数据容器
import java.util.concurrent.ConcurrentHashMap; import java.util.Map; public class RequestDataHolder { private final Map<String, Object> data = new ConcurrentHashMap<>(); public void put(String key, Object value) { data.put(key, value); } public Object get(String key) { return data.get(key); } public boolean containsKey(String key) { return data.containsKey(key); } }
步骤2:修改RequestFilter实现
@Component public class RequestFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { // 创建可变数据容器,放入Context传递给下游 RequestDataHolder dataHolder = new RequestDataHolder(); // 在响应提交前读取容器中的数据 exchange.getResponse().beforeCommit(() -> Mono.fromRunnable(() -> { System.out.println(dataHolder.containsKey("abc")); System.out.println(dataHolder.get("abc")); })); BodyCaptureExchange bodyCaptureExchange = new BodyCaptureExchange(exchange); // 将容器写入Context,传递给Controller return chain.filter(bodyCaptureExchange) .contextWrite(context -> context.put("REQUEST_DATA_HOLDER", dataHolder)); } }
步骤3:修改Controller方法
public Mono<ResponseEntity<Response>> post(@RequestBody Mono<Request> request) { return request.flatMap(rq -> service.requestProcess(rq) .map(res -> ResponseEntity.ok().body(res))) .contextWrite(context -> { // 从Context中取出容器,存入共享数据 RequestDataHolder holder = context.get("REQUEST_DATA_HOLDER"); holder.put("abc", "abc"); return context; }); }
关键说明
- 可变容器
RequestDataHolder使用ConcurrentHashMap保证线程安全,适配WebFlux的异步场景。 contextWrite是Reactor 3.2+推荐的Context写入方式(替代旧的subscriberContext),和你的Reactor 3.3.14版本完全兼容。- 响应提交阶段的
beforeCommit回调直接访问同一个dataHolder对象,能获取到Controller修改后的最新数据。
内容的提问来源于stack exchange,提问作者SoT
相关产品推荐
相关产品推荐

