关键在于分离业务语义码(code)与协议层HTTP状态码(HttpStatus),通过ResponseEntity+Result封装及@RestControllerAdvice实现精准映射,确保REST规范与前端拦截兼容。

Spring Boot 处理自定义 HTTP 状态码与统一 Result 结构体的适配封装,关键在于**分离语义层状态码(code)与协议层 HTTP 状态码(HttpStatus)**,再通过 `@RestControllerAdvice` 和 `ResponseEntity` 实现精准映射。不是简单把 Result.code 直接当 HTTP 状态码返回,否则会丢失 REST 语义、干扰网关或前端拦截逻辑。
明确两层状态码职责
统一 Result 中的 code 字段属于业务语义码(如 20001 表示“用户不存在”,40002 表示“库存不足”),用于前端展示和业务分支判断;HTTP 状态码属于协议层信号(如 200、400、401、404、500),应由 Spring MVC 按照请求结果性质自动或显式设置,指导客户端缓存、重试、跳转等行为。
- 成功响应(含数据或空操作)→ 原则上用 200 OK,少数场景如创建资源用 201 Created
- 客户端错误(参数校验失败、权限不足、资源不存在)→ 对应 4xx 系列,如 400、401、403、404
- 服务端错误(未捕获异常、数据库连接失败)→ 统一返回 500 Internal Server Error
用 ResponseEntity + Result 封装控制器返回
避免直接 return Result<T>,改用 ResponseEntity<Result<T>>,在 Controller 层显式控制 HTTP 状态码:
@GetMapping("/user/{id}")
public ResponseEntity<Result<User>> getUser(@PathVariable Long id) {
User user = userService.findById(id);
if (user == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Result.fail(40401, "用户不存在"));
}
return ResponseEntity.ok(Result.success(user));
}
这样既保持了 Result 结构体的统一性(code=40401、message="用户不存在"、data=null),又让 HTTP 层返回标准的 404 状态,符合 REST 规范,也兼容 OpenAPI 文档生成和前端 axios/fetch 的 error 拦截。
全局异常处理器中完成双向映射
在 `@ControllerAdvice` 中处理异常时,需根据异常类型决定 HTTP 状态码,并填充 Result 的业务 code 和 message:
- 遇到
IllegalArgumentException或自定义ParamException→ 返回 400 + Result.code=40001 - 遇到
AccessDeniedException或AuthenticationException→ 返回 401/403 + Result.code=40101/40301 - 遇到
EntityNotFoundException→ 返回 404 + Result.code=40401 - 其他未预期异常 → 返回 500 + Result.code=50001
示例片段:
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<Result<?>> handleNotFound(EntityNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Result.fail(40401, e.getMessage()));
}
可选:用注解简化 HTTP 状态码绑定
若项目中大量接口需按枚举快速设定 HTTP 状态,可定义一个轻量注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HttpStatusMapping {
HttpStatus value() default HttpStatus.OK;
}
配合一个 AOP 或增强型 `ResponseBodyAdvice`,在序列化前读取该注解并包装为 `ResponseEntity`。但对多数项目,直接在 Controller 或异常处理器里写 `ResponseEntity.status(...)` 更直观、易调试、无隐式行为。
不复杂但容易忽略:HTTP 状态码影响浏览器缓存、CDN 行为、前端拦截器分类(比如只 catch 4xx 不 catch 5xx),而 Result.code 只服务于业务逻辑。两者各司其职,才能兼顾规范性与实用性。


















