Spring Boot REST API如何选择正确的HTTP响应码?
遵循REST规范:优先使用标准HTTP状态码,自定义码作为补充
你的当前实现虽然能正常工作,但不符合REST API的设计规范,更推荐结合标准HTTP状态码+自定义业务状态码的方式,原因如下:
为什么全返回200不合理?
- 违背HTTP协议语义:HTTP状态码是协议的核心组成部分,本身就承载了请求结果的语义(比如201表示资源已创建、401表示未授权、409表示资源冲突)。全返回200会让这些语义丢失,客户端必须解析响应体才能判断请求结果,增加了客户端的处理复杂度。
- 工具链兼容性差:API网关、监控系统、调试工具(比如Postman)都是基于HTTP状态码做请求过滤、告警、统计的。全200会导致这些工具无法识别错误请求,比如监控无法及时告警5xx级别的服务器错误。
- 语义模糊:自定义状态码需要客户端开发者额外查阅文档对应含义,而标准HTTP状态码是行业通用的,开发者一看就懂,降低了沟通成本。
合理的实现方式:标准HTTP状态码为主,自定义业务码为辅
你可以保留自定义状态码来区分更细的业务场景,但必须用标准HTTP状态码来标识请求的整体结果:
1. 成功场景的状态码选择
- 创建资源(比如
/new-user):使用HttpStatus.CREATED(201),符合“资源已成功创建”的语义。 - 查询/更新资源:使用
HttpStatus.OK(200)。 - 删除资源:可以使用
HttpStatus.NO_CONTENT(204)表示无返回内容的成功。
修改后的创建用户示例:
@PostMapping("/new-user") public ResponseEntity<SuccessResponse<UserDto>> createUser( @Valid @RequestBody UserDto userDto) { UserDto createdUserDto = this.userService.createUser(userDto); SuccessResponse<UserDto> successResponse = new SuccessResponse<>( AppConstants.SUCCESS_CODE, AppConstants.SUCCESS_MESSAGE, createdUserDto ); return new ResponseEntity<>(successResponse, HttpStatus.CREATED); // 用201替代200 }
2. 异常场景的状态码选择
根据异常类型匹配对应的HTTP状态码:
- 重复资源(比如重复注册):
HttpStatus.CONFLICT(409) - 令牌过期/未授权:
HttpStatus.UNAUTHORIZED(401) - 参数校验失败:
HttpStatus.BAD_REQUEST(400) - 资源未找到:
HttpStatus.NOT_FOUND(404) - 服务器内部错误:
HttpStatus.INTERNAL_SERVER_ERROR(500)
修改后的异常处理示例:
@ExceptionHandler(DuplicateResourceException.class) public ResponseEntity<ApiResponse> duplicateResourceFoundException(DuplicateResourceException ex) { ApiResponse apiResponse = new ApiResponse( ex.getMessage(), "2002", // 自定义业务码 AppConstants.ERROR_MESSAGE ); return new ResponseEntity<>(apiResponse, HttpStatus.CONFLICT); // 用409替代200 } @ExceptionHandler(TokenExpiredException.class) public ResponseEntity<ApiResponse> tokenExpiredException(TokenExpiredException ex) { ApiResponse apiResponse = new ApiResponse( "Token is expired", "2001", // 自定义业务码 AppConstants.ERROR_MESSAGE ); return new ResponseEntity<>(apiResponse, HttpStatus.UNAUTHORIZED); // 用401替代200 }
3. 自定义状态码的作用
自定义状态码用来在同一个HTTP状态码下区分更细的业务场景,比如:
- 同样是400(参数错误),自定义码可以区分“必填项缺失”“格式错误”“长度超限”等
- 同样是401(未授权),可以区分“令牌过期”“令牌无效”“未登录”等
这种方式既遵循了REST规范,又保留了业务细节,对客户端开发(可以用HTTP状态码做通用逻辑,比如401跳登录)和服务端运维(可以用状态码监控错误)都更友好。
内容的提问来源于stack exchange,提问作者ayush
相关产品推荐
相关产品推荐

