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
相关产品推荐
相关产品推荐

