Spring Boot REST API中@PutMapping与@DeleteMapping的HTTP状态码选择及实现疑问
Spring Boot REST API中@PutMapping与@DeleteMapping的HTTP状态码选择及实现疑问
兄弟,我太懂你这种纠结了——之前图省事全用HttpStatus.OK确实省心,但要做规范的REST API,状态码的选择真得抠细节。咱们一步步捋清楚PUT和DELETE该用啥状态码,还有你提到的NO_CONTENT带响应体的问题。
关于PUT请求的状态码选择
PUT的核心语义是更新已存在资源,或按客户端指定ID创建新资源,所以状态码分两种场景选:
- 如果是更新已存在的资源:返回
200 OK是最常用也最合理的,这时可以把更新后的资源数据或者操作结果放进响应体,方便客户端确认更新效果。 - 如果是通过PUT创建了新资源(比如客户端指定ID来创建分类):这时候应该返回
201 Created,同时记得在响应头的Location字段带上新资源的URI(比如/categories/123),这是REST风格的标准做法。
绝大多数常规业务场景里,PUT都是用来更新已存在资源,所以返回200 OK是没问题的。
关于DELETE请求的状态码选择
DELETE的核心是删除指定资源,状态码的选择取决于你要不要给客户端返回额外信息:
- 删除成功且不需要返回任何内容:返回
204 No Content是HTTP规范里的标准做法——这里要注意,204的响应不应该带响应体,虽然有些客户端能勉强解析,但不符合规范,而且部分代理服务器可能会直接忽略这个body,导致客户端拿不到数据。 - 删除成功且需要返回业务反馈(比如操作时间戳、删除的资源ID):这时候返回
200 OK完全没问题,把反馈信息放进响应体返回就行,这种场景更偏向业务化的交互,很合理。
对你的DELETE实现代码的点评
先看你最开始写的那段代码:
@DeleteMapping("/categories/{id}") public ResponseEntity<ApiResponse<CommandResponse>> deleteById(@PathVariable long id) { final CommandResponse response = categoryService.deleteById(id); return ResponseEntity .status(HttpStatus.NO_CONTENT) .body(new ApiResponse<>(Instant.now(clock).toEpochMilli(), SUCCESS, response)); }
这段的问题就是用NO_CONTENT却带了响应体,不符合HTTP规范,不建议这么写——要么把状态码改成OK,要么去掉响应体。
再看你后来的两个优化方案:
- 方案#1:返回
200 OK并携带业务元数据
@DeleteMapping("/categories/{id}") public ResponseEntity<ApiResponse<Void>> deleteById(@PathVariable long id) { categoryService.deleteById(id); return ResponseEntity.ok(new ApiResponse<>(Instant.now(clock).toEpochMilli(), SUCCESS)); }
这个方案很适合需要给客户端返回操作成功标识、时间戳这类业务元数据的场景,完全符合规范,客户端也能清晰拿到反馈,非常实用。
- 方案#2:返回
204 No Content不带响应体
@DeleteMapping("/categories/{id}") public ResponseEntity<ApiResponse<Void>> deleteById(@PathVariable long id) { categoryService.deleteById(id); return ResponseEntity .status(HttpStatus.NO_CONTENT) .build(); }
这是完全符合HTTP规范的标准实现,适合不需要返回任何额外信息的轻量场景,简洁又合规。
总结建议
- PUT:更新现有资源用
200 OK;通过PUT创建新资源用201 Created - DELETE:无需返回内容用
204 No Content;需要业务反馈用200 OK
备注:内容来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

