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

Spring WebFlux如何通过@RequestBody同时获取两种格式的请求体

问题原因分析
  • 你的两种写法都存在逻辑错误:
    1. 第一种写法加了两个@RequestBody注解:Spring WebFlux基于响应式流实现,HTTP请求体是仅可消费一次的数据流,两次绑定@RequestBody相当于要重复读取请求流,自然会抛出Only one connection receive subscriber allowed异常。
    2. 第二种写法没有给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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 11:06:02