API 错误码设计指南(免费版)
一、它解决什么问题
糟糕的错误响应让三方都难受:
1. 客户端:只拿到"系统错误",不知道该重试、改参数还是提示用户;
2. 用户:看到一堆英文/乱码,无从下手;
3. 运维/开发:没有唯一编码,日志里搜不到、问题无法定位。
统一错误码:给每类错误一个唯一、稳定、可读的编码,配合 HTTP 状态码与结构化消息,
让错误可被程序判断、可被人检索、可被日志追踪。
二、错误码设计原则
- 唯一性:一类错误一个码,不要一码多义;
- 稳定性:错误码一旦发布就是契约,不随意改数字/语义;
- 可读性:编码能看出模块与类别(如
USER-404-001); - 可枚举:全部错误码集中注册、有文档,不允许散落硬编码;
- 可处理:能区分"可重试"(如 429/503)与"不可重试"(如 400/404)。
三、统一编码结构
推荐三段式:模块码 - HTTP类别 - 序号
USER-404-001
│ │ └ 模块内该类错误的序号(001~999)
│ └ HTTP 状态类别(404 未找到)
└ 业务模块(USER 用户)
- 模块码:2-8 位大写字母(USER/ORDER/PAY/STOCK);
- 类别:直接用 HTTP 状态码,语义统一、无需自造分类;
- 序号:模块+类别内自增,三位补零。
四、HTTP 状态码正确使用
| 码 | 语义 | 客户端处理 |
|---|---|---|
| 400 | 参数错误 | 不可重试,改参数 |
| 401 | 未认证 | 重新登录/带凭证 |
| 403 | 无权限 | 不可重试 |
| 404 | 资源不存在 | 不可重试 |
| 409 | 状态冲突 | 视场景(如并发修改) |
| 422 | 语义校验失败 | 不可重试,改数据 |
| 429 | 触发限流 | 按 Retry-After 退避重试 |
| 500 | 服务端内部错误 | 可有限重试 |
| 503 | 服务不可用 | 退避重试 |
> 不要把所有错误都返回 200 然后在 body 里放成败,也不要业务错误一律 500;
> HTTP 状态码表达"请求处理结果类别",业务错误码表达"具体是什么错"。
五、标准错误响应体
{
"code": "USER-404-001",
"message": "用户不存在",
"detail": "uid=123",
"trace_id": "trace-abc"
}
code:稳定错误码,供程序判断;message:可读、面向用户的消息(不泄露堆栈/敏感信息);detail:可选,字段级校验错误、上下文;trace_id:贯穿日志,便于报障定位。
六、注册与文档
- 错误码集中注册(一张表/一个注册表模块),禁止各处随手写字符串;
- 提供错误码清单文档:码、HTTP、消息、是否可重试、说明;
- 新增错误码走统一入口,自动分配序号、防重复;
- 对外 API 的错误码随接口文档发布。
七、版本演进
- 错误码是对外契约:只增不删不改;废弃的码标记 deprecated 但不复用;
- 语义变化用新码,避免老客户端误判;
- 新增模块用新模块码,不挤占已有编码。
八、落地检查清单
- [ ] 确定统一编码结构并全团队执行
- [ ] HTTP 状态码与业务错误码职责清晰
- [ ] 标准响应体含 code/message/trace_id
- [ ] 错误码集中注册、有文档、防重复
- [ ] 标明可重试/不可重试,客户端有对应策略
- [ ] 消息不泄露堆栈与敏感信息