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

Spring Webflux RouterFunction端点返回Mono结果异常:返回{"scanAvailable":true}的解决方法

Ah, I see the issue here! The problem is that you're using map instead of flatMap when chaining your reactive operations, which leads to a nested Mono<Mono<Object>> instead of the flat Mono<Object> you need. Let me break this down and show you how to fix it.

What's Going Wrong?

When you call getUserPrincipal().map(service::getSomething), the map operator takes each UserPrincipal and converts it into the result of service.getSomething()—which is a Mono<Object>. This means you end up with a Mono<Mono<Object>> (a Mono wrapping another Mono). When you pass this to fromPublisher, it treats the inner Mono as a regular object and serializes its internal state (like the {"scanAvailable": true} you're seeing) instead of subscribing to it and returning the actual data.

The Fix: Use flatMap Instead of map

flatMap is designed specifically for asynchronous operations that return a Publisher (like Mono or Flux). It will subscribe to the inner Mono, wait for it to emit data, and flatten that result into the outer stream—giving you a clean Mono<Object> that emits your actual response data.

Here's your corrected getExample method:

private Mono<ServerResponse> getExample(ServerRequest request) {
    return getUserPrincipal()
            // Use flatMap to unwrap the inner Mono returned by service.getSomething()
            .flatMap(service::getSomething)
            // bodyValue() directly accepts the emitted object
            .flatMap(result -> ServerResponse.ok().bodyValue(result))
            .log();
}

Or even more concise: since ServerResponse.body() natively supports Publisher types, you can skip the extra flatMap and pass the flattened stream directly:

private Mono<ServerResponse> getExample(ServerRequest request) {
    return ServerResponse.ok()
            .body(getUserPrincipal().flatMap(service::getSomething), Object.class)
            .log();
}

Why This Works

Spring WebFlux's body() method is built to handle Mono/Flux out of the box—you don't need to manually wrap it with fromPublisher (the framework does that under the hood). By passing the flattened Mono<Object> directly, the framework will subscribe to it, wait for the data to be fetched from your downstream service, and send that data as the response body.

Bonus: Add Safety to Principal Extraction

To avoid unexpected ClassCastExceptions, you can add checks to your getUserPrincipal() method:

private Mono<UserPrincipal> getUserPrincipal() {
    return ReactiveSecurityContextHolder.getContext()
            .map(SecurityContext::getAuthentication)
            .filter(auth -> auth.getPrincipal() instanceof UserPrincipal)
            .map(auth -> (UserPrincipal) auth.getPrincipal())
            .switchIfEmpty(Mono.error(new UnauthorizedException("Invalid user principal")));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 20:07:35