You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux:Controller与Filter通过Context共享数据失败求助

问题原因分析
  1. Reactor Context的单向传递特性:Reactor Context是不可变对象,仅向下游订阅者传递。下游通过subscriberContext/contextWrite新增的Context条目无法回溯到上游操作中。你在Filter中chain.filter(...)之后添加的subscriberContext,是给Controller执行完成后的后续操作设置Context,而非传递给Controller;Controller修改的Context是下游生成的新实例,上游Filter的beforeCommit回调无法获取。
  2. 无效的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 16:55:21