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

Postman调用Spring接口报错:无法发送请求体,请求流已关闭

排查Spring接口Postman调用时的HttpMessageNotReadableException(Stream closed)问题

这个错误的根源非常明确:你在同一个接口方法里使用了多个@RequestBody注解,这完全违反了HTTP请求的基本规则,也和Spring的请求体解析逻辑冲突。

为什么会报错?

HTTP请求的请求体是一个一次性的字节流,Spring在解析第一个@RequestBody参数时,会把整个流读取完毕并关闭。当它尝试解析第二个、第三个@RequestBody时,流已经处于关闭状态,自然就抛出了java.io.IOException: Stream closed异常。

看你的代码就能直接定位问题:

@PostMapping()
public ResponseEntity<Object> postAccounts(
    @RequestHeader(value = "client-id", required = true) String clientId,
    @RequestHeader(value = "X-client-Global-Id", required = false) String clientGlobalID,
    @RequestHeader(value = "Authorization", required = true) String authorization,
    @Valid @RequestBody(required = true) String inputContract,
    @RequestBody(required = true)String nameInput, // 重复使用@RequestBody
    @RequestBody(required = true) Boolean state) { // 再次重复使用!
    return new ResponseEntity<>(inputContract, HttpStatus.OK);
}

解决办法

最规范且通用的解决方案是封装统一的请求体DTO,具体步骤如下:

  1. 创建一个包含所有请求体字段的DTO类
import jakarta.validation.constraints.NotNull; // Spring Boot 3+用jakarta包;Spring Boot 2用javax包
import lombok.Data; // 用Lombok简化代码,无需手动编写getter/setter

@Data
public class AccountCreateRequest {
    @NotNull // 按需添加校验注解,确保字段非空
    private String inputContract;
    
    @NotNull
    private String nameInput;
    
    @NotNull
    private Boolean state;
}
  1. 修改接口方法,用DTO统一接收请求体
@PostMapping()
public ResponseEntity<Object> postAccounts(
    @RequestHeader(value = "client-id", required = true) String clientId,
    @RequestHeader(value = "X-client-Global-Id", required = false) String clientGlobalID,
    @RequestHeader(value = "Authorization", required = true) String authorization,
    @Valid @RequestBody(required = true) AccountCreateRequest request) {
    // 通过request.getInputContract()等方法获取对应字段
    return new ResponseEntity<>(request.getInputContract(), HttpStatus.OK);
}
  1. 调整Postman的调用方式
    在Postman中选择Body -> raw -> JSON,传入符合DTO结构的JSON数据:
{
  "inputContract": "你的合同字符串内容",
  "nameInput": "测试名称",
  "state": true
}

其他可选方案(不推荐用于复杂参数)

如果你的参数都是简单类型,也可以考虑把nameInput和state放到请求参数(Query Parameters)里,但这种方式只适合少量简单数据,复杂内容还是用DTO封装请求体更合理、更易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 16:22:46