Spring Webflux响应式链中如何在doOnNext里获取原始请求对象?
解决方案
方案一:通过flatMap关联请求与结果(推荐)
这种方式直接简洁,无需额外上下文传递,还能避免请求体重复解析的问题:
修改控制器代码:
@PostMapping("url") public Mono<MyResponse> getMyResponse(@RequestBody Mono<MyRequest> myRequestMono) { // 缓存请求Mono,防止多次订阅导致请求体被重复解析 Mono<MyRequest> cachedRequest = myRequestMono.cache(); return cachedRequest.flatMap(request -> urlService.getUrl(Mono.just(request)) .doOnNext(url -> { // 直接访问请求对象的目标字段,比如id System.out.println("Generated URL: Successfully for request ID: " + request.getId()); }) .map(dto -> MyResponse.builder().url(dto).build()) ) .doOnError(e -> System.out.println("Error: " + e.getMessage())); }
说明:
cache()方法用于缓存请求Mono,避免因控制器和服务的多次订阅触发请求体重复解析。- 通过
flatMap将原始请求对象与服务返回结果绑定,在doOnNext中可以直接访问请求的所有字段,完全不需要修改服务类逻辑。
方案二:正确使用Reactor上下文(适合跨组件传递场景)
如果需要在多个组件间共享请求对象,可通过Reactor上下文传递,但要避免重复读取请求体:
修改控制器代码:
@PostMapping("url") public Mono<MyResponse> getMyResponse(@RequestBody Mono<MyRequest> myRequestMono) { return myRequestMono .flatMap(request -> urlService.getUrl(Mono.just(request)) .map(url -> MyResponse.builder().url(url).build()) // 将请求对象存入上下文 .contextWrite(ctx -> ctx.put("MY_REQUEST", request)) ) .transformDeferredContextual((responseMono, contextView) -> responseMono.doOnNext(response -> { // 从上下文中取出请求对象 MyRequest request = contextView.get("MY_REQUEST"); System.out.println("Generated URL: Successfully for request ID: " + request.getId()); }) ) .doOnError(e -> System.out.println("Error: " + e.getMessage())); }
说明:
- 直接在控制器中将请求放入上下文,避免了WebFilter重复读取请求体导致控制器无法获取数据的问题。
transformDeferredContextual用于延迟访问上下文,确保上下文已被正确填充后再读取。
你之前的上下文方案失败原因
你尝试的WebFilter方案存在核心问题:Spring Webflux中请求体是Flux<DataBuffer>,只能被订阅/读取一次。如果WebFilter先解析了请求体,控制器的@RequestBody将无法再读取到数据,直接导致请求失败,因此这种方式不适用你的场景。
内容的提问来源于stack exchange,提问作者pvpkiran
相关产品推荐
相关产品推荐

