错误码像打针——不愉快,但极有用。它是 API 响应阶段开发者向用户传达失败的基本方式,也是错误发生后启动排查的第一步。
用户无法选择何时出错、错在哪;错误响应因此成了出错时唯一「恒定、一致」的沟通通道。一个好错误码同时完成两件事:澄清现状 + 传达本该怎样用。例如 401 Unauthorized – Please Pass Token,既点明「未授权」,又告诉用户「本接口需要传 token」——花极少数据量,却价值巨大。
错误码几乎是你在 API 响应里最不想见到的东西,但它又极其有用——它是开发者向用户传达「哪里错了、为什么、怎么修」的唯一稳定通道。本文编译自 Nordic APIs《Best Practices for API Error Handling》(2017-06-15,作者 Kristopher Sandoval),拆解 HTTP 状态码 1XX–5XX、好/坏错误码的三个标准,并结合 RFC 7807 / RFC 9457 Problem Details 给出可直接套用的结构化错误模板。
错误码像打针——不愉快,但极有用。它是 API 响应阶段开发者向用户传达失败的基本方式,也是错误发生后启动排查的第一步。
用户无法选择何时出错、错在哪;错误响应因此成了出错时唯一「恒定、一致」的沟通通道。一个好错误码同时完成两件事:澄清现状 + 传达本该怎样用。例如 401 Unauthorized – Please Pass Token,既点明「未授权」,又告诉用户「本接口需要传 token」——花极少数据量,却价值巨大。
虽说有其他协议,但 HTTP 状态码主导了 API 沟通,厂商自定义码也大多从这套区间派生。理解区间含义,等于知道了「错在谁身上」:
| 区间 | 含义 | 责任方 | 典型码 |
|---|---|---|---|
| 1XX | 信息/协议状态 | — | 100 Continue、101 Switching Protocols |
| 2XX | 成功 | — | 200 OK、201 Created、202 Accepted |
| 3XX | 重定向/资源位置变了 | — | 301 Moved Permanently |
| 4XX | 客户端错误 | 客户端 | 400、404、414 URI Too Long、429 Too Many Requests |
| 5XX | 服务器错误 | 服务器 | 502 Bad Gateway、503 Service Unavailable |
关键区别:4XX 是客户端的锅(请求有问题),5XX 是服务器的锅(有效请求仍失败)。429 用于限流,414 提示 GET 数据太长该改 POST。
一个「真有用」的错误码必须满足三条:
BR0x0071);若参考表含状态码映射,它甚至可替代裸状态码。裸 400 Bad Request 只告诉你「客户端错了」,却不说错在哪——这是「看似功能、实则不功能」的典型。
光有机器码不够,得在响应体里给上下文。下面这个比裸 400 好,但仍差一口气——它只给了内部参考号,用户还得去查文档:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{ "error" : "REQUEST - BR0x0071" }稍加改造,既保留参考号又给可操作信息:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{ "error" : "Bad Request - Your request is missing parameters.
Please verify and resubmit. Issue Reference Number BR0x0071" }这下用户知道「参数缺失」,起码有了排查起点。记住:为机器编码 ≠ 为人编码,两者都要兼顾——状态码和参考号给机器,人话信息给人。
Twitter:400 + 自定义码 215 + 信息 Bad Authentication data——既说清原因,又给内部码备查。
Facebook Graph:返回 type: OAuthException、code: 2500、fbtrace_id,并明确指出「picture 字段重复定义」,还提示该行为在 2.1 前才允许——顺带沟通了版本变更。
Bing(最佳范例):code: 1001 + Message: Required parameter is missing + 点名缺失参数 SearchRequest.AppId + 附 HelpUrl 解决链接。机器可读码、人话摘要、错误定位、解决入口,四样齐全。
Spotify:5XX 罕见但真实存在。502 Bad Gateway 看似 opaque,价值在响应头与日志里的生产环境标记——让人判断是「网关/负载」问题而非外部因素。
各家错误体五花八门({error:...}、{code,msg}、{errors:[...]}),客户端得为每个 API 写专用解析逻辑。IETF 的 RFC 7807 后来演进为 RFC 9457(Problem Details for HTTP APIs),定义了标准错误结构,新项目应直接采用:
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
"type": "https://api.example.com/errors/invalid-input",
"title": "Invalid Input Parameters",
"status": 422,
"detail": "The 'email' field must use user@domain.com format",
"instance": "/users/registration/2026-05-28/8042",
"errors": [
{ "detail": "must be a valid email address", "pointer": "#/email" }
]
}五个标准字段:type(URI,定位错误类型)、title(稳定短摘要)、status(HTTP 码)、detail(本次具体说明)、instance(用于日志关联的请求标识)。扩展字段(如 errors 数组)可一次返回全部校验错误,避免「改一个、交一个、又报一个」的折磨循环。
错误响应是信息源:既要告知问题,也要给出解法。平衡可用性(人话)与简洁性(机器可解析),平衡点找对,威力巨大。
落地清单:① 用最具体的状态码(邮箱校验失败用 422 而非笼统 400);② 错误体带 type/title/status/detail;③ 写操作失败给 Retry-After(429/503);④ 生产环境绝不外泄堆栈/SQL;⑤ 全局异常处理器统一序列化,路由只管业务;⑥ 给每个错误附带 instance 关联 ID 便于排障。