后端接口如果没有统一响应结构,前端就要面对各种形状的数据:有的直接返回对象,有的返回字符串,出错时可能返回默认错误页。这个项目的做法是所有
REST 接口都返回 ApiResponse<T>。
一、响应结构
{
"success": true,
"code": 0,
"message": "操作成功",
"data": {},
"timestamp": 1723017600000
}
字段含义很直接:
success:快速判断业务是否成功。code:细粒度错误码。message:给调用方看的提示。data:业务数据。timestamp:响应生成时间。
二、错误码分段
0 成功
-1 通用失败
100 参数校验失败
101 请求体格式错误
102 资源不存在
401 未认证
403 无权限
500 服务内部错误
503 服务不可用
这个分段刻意和 HTTP 状态语义接近,但不是简单等同。业务服务内部失败时 HTTP 可以是 200,响应体里的 code 再表达具体业务结果。
三、用接口承接自定义错误码
标准错误码放在 ApiResponseEnum 中。业务模块要扩展自己的错误码时,不需要改公共枚举,只要实现 ErrorCode:
public interface ErrorCode {
int code();
String message();
}
然后业务异常可以直接接收这个接口:
throw new BusinessException(ApiResponseEnum.USER_NOT_FOUND);
这样公共模块只依赖抽象,不需要知道每个业务模块有哪些错误码。
四、静态工厂让调用侧更清楚
ApiResponse 提供了这些入口:
ApiResponse.success(data);
ApiResponse.successMessage("操作成功");
ApiResponse.failureMessage("参数非法");
ApiResponse.failure(ApiResponseEnum.NOT_FOUND);
这里有个小设计点:successMessage 和 failureMessage 显式带 Message,避免当 T=String 时和 success(Object)、
failure(Object) 产生重载歧义。
五、避坑点
- 不要把数据库实体字段直接塞进错误提示。
- 未预期异常不要把完整堆栈返回给前端。
success字段判断要防null,所以内部使用Boolean.TRUE.equals(success)。- 前端不能只判断 HTTP 200,还要读取
success和code。