Spring WebFlux如何通过@RequestBody同时获取两种格式的请求体
问题原因分析
- 你的两种写法都存在逻辑错误:
- 第一种写法加了两个
@RequestBody注解:Spring WebFlux基于响应式流实现,HTTP请求体是仅可消费一次的数据流,两次绑定@RequestBody相当于要重复读取请求流,自然会抛出Only one connection receive subscriber allowed异常。 - 第二种写法没有给
PlayCommand加@RequestBody注解:Spring会将无注解的自定义Java类视为普通表单/查询参数模型,只会从URL参数、表单字段中读取值填充,不会解析JSON请求体,所以所有字段都是null。
- 第一种写法加了两个
可行解决方案
Spring WebFlux本身不支持原生同时绑定两种格式的请求体,最优实现方式是只读取一次原始JSON字符串,手动解析为DTO,该操作的性能开销极低,不属于多余操作:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController public class PlayController { // 注入Spring默认配置好的ObjectMapper private final ObjectMapper objectMapper; public PlayController(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @PostMapping("/play") public Mono<PlayResponse> play(@RequestBody String jsonBody) throws Exception { // 一次解析同时拿到两种格式 PlayCommand parsedBody = objectMapper.readValue(jsonBody, PlayCommand.class); // 后续业务逻辑可以同时使用jsonBody和parsedBody // ... 你的业务代码 } }
如果需要完全贴合响应式无阻塞写法,可以接收Mono包装的原始字符串,在流操作中完成解析:
@PostMapping("/play") public Mono<PlayResponse> play(@RequestBody Mono<String> jsonBodyMono) { return jsonBodyMono.handle((jsonBody, sink) -> { try { PlayCommand parsedBody = objectMapper.readValue(jsonBody, PlayCommand.class); // 执行业务逻辑返回响应 sink.next(new PlayResponse()); } catch (Exception e) { sink.error(e); } }); }
内容的提问来源于stack exchange,提问作者Volodya Lombrozo
相关产品推荐
相关产品推荐

