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

Spring WebFlux接口返回空响应求助:/auth/test无法返回用户名

问题根源与修复方案

嘿,我一眼就发现问题所在了——你重复订阅了Reactor的冷流,导致后续处理拿不到请求体数据,所以返回了空响应。

在Spring WebFlux依赖的Reactor框架里,Mono和Flux都是冷流:简单说就是只有当有订阅者的时候才会生成/读取数据,而且每个订阅都会触发一次全新的数据获取过程。你代码里的这行:

jwtRequestMono.subscribe(v -> System.out.println(v.getUsername() + ":" + v.getPassword()));

提前手动订阅了jwtRequestMono,这会立刻触发请求体的解析和读取。等后面的flatMap再去订阅这个Mono时,请求体已经被读完了,自然拿不到任何数据,flatMap里的逻辑根本不会执行,最后就返回了空响应。

而你测试硬编码字符串正常,是因为硬编码的Mono本身就持有现成的数据,不需要依赖读取请求体,所以不受订阅问题的影响。

两种修复方式

方式1:用doOnNext替代subscribe做日志(推荐)

doOnNext是Reactor的副作用操作符,它不会主动订阅流,只是在流产生数据的时候执行日志这类副作用操作,完全不会消耗数据流。这样后续的flatMap依然能正常获取请求体数据:

public Mono<ServerResponse> test(ServerRequest request) {
    System.out.println("Start test ");
    Mono<JwtRequest> jwtRequestMono = request.bodyToMono(JwtRequest.class);
    return jwtRequestMono
            .doOnNext(v -> System.out.println(v.getUsername() + ":" + v.getPassword()))
            .flatMap(j -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(j.getUsername()));
}

方式2:缓存流数据(适合确实需要多次使用的场景)

如果你真的需要在多个地方复用这个流的数据,可以用cache()操作符把数据缓存起来,这样多次订阅也只会触发一次请求体读取:

public Mono<ServerResponse> test(ServerRequest request) {
    System.out.println("Start test ");
    Mono<JwtRequest> jwtRequestMono = request.bodyToMono(JwtRequest.class).cache();
    jwtRequestMono.subscribe(v -> System.out.println(v.getUsername() + ":" + v.getPassword()));
    return jwtRequestMono
            .flatMap(j -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(j.getUsername()));
}

不过还是更推荐第一种方式,因为在WebFlux的请求处理方法里,手动调用subscribe其实是不符合响应式编程规范的——框架会负责最终的订阅工作,我们只需要构建好数据流的处理逻辑就够了。

内容的提问来源于stack exchange,提问作者v78

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:27:29