定位:02补 讲「动词合同」;本文讲「结果合同」——状态码。规范底本为 RFC 9110;文中「行业共识」指 REST/JSON API 里被网关、客户端库、监控广泛默认的用法,不是业务法条。最终响应仍由你的 handler 决定,但选错码会误导重试、告警与缓存。
0. 先记住:状态码是给机器看的合同
| 角色 | 靠状态码做什么 |
|---|---|
| 浏览器 / 客户端 SDK | 是否重试、是否跳转、是否弹登录 |
| 反向代理 / CDN | 是否缓存、是否熔断上游 |
| 监控 / SLO | 5xx 算故障;4xx 常算客户端问题(需按业务再切) |
| 人 | 一眼分「谁的锅」 |
费曼一句:方法说「我想干什么」,状态码说「这件事结局如何、错在哪一侧」。body 里的 { "error": "..." } 是给人看的细节,不能代替状态码。

段末注释:HTTP 状态码(status code)是响应起始行中的三位数字,表示请求处理结果的类别与具体含义;后文直接写数字(如 404)。
1. 五大家族(行业第一刀)
| 族 | 范围 | 共识含义 | API 日常频率 |
|---|---|---|---|
| 1xx | 100–199 | 中间态 / 协议控制(继续、切换协议) | 低(框架/协议层居多) |
| 2xx | 200–299 | 成功 | 高 |
| 3xx | 300–399 | 重定向(去别处拿结果) | 中(短链、www、HTTPS) |
| 4xx | 400–499 | 客户端错(请求本身有问题) | 高 |
| 5xx | 500–599 | 服务端错(服务器或上游挂了) | 高(告警主战场) |
粗分责任:
1 | 2xx → 办成了(或按约定受理了) |
2. API 必会清单(按共识强度)
下列为 JSON API / FastAPI 项目里几乎人人默认的集合;冷门码放 §5。

2.1 2xx — 成功
| 码 | 名称(常称) | 行业共识用法 | 典型搭配 | 局限 / 注意 |
|---|---|---|---|---|
| 200 | OK | 通用成功;GET/PUT/PATCH/动作型 POST 有正文 | 读资源、更新后回写表示 | 别用 200 包装业务失败(反模式) |
| 201 | Created | 新建成功;常带 Location 指向新资源 |
POST 集合创建;有时 PUT 新建 |
应真的创建了资源;仅「受理」用 202 |
| 202 | Accepted | 已受理、尚未做完(异步) | 长任务、入队 | 需另提供查询状态的接口 |
| 204 | No Content | 成功且无响应体 | DELETE、PUT/PATCH 不回写 |
客户端勿解析 body;浏览器对 DELETE 友好 |
2.2 3xx — 换地方(API 里少用但要识)
| 码 | 共识用法 | API 注意 |
|---|---|---|
| 301 | 永久重定向 | 改域名/路径时;部分客户端会把 POST 改成 GET |
| 302 / 303 | 临时跳转 / See Other | 表单 POST 后跳转结果页(PRG);纯 JSON API 少用 |
| 304 | Not Modified | 条件 GET(If-None-Match)命中缓存 |
| 307 / 308 | 保留方法的临时/永久重定向 | 需要保持 POST 时优于 301/302 |
2.3 4xx — 客户端侧
| 码 | 名称 | 行业共识 | 与易混码 |
|---|---|---|---|
| 400 | Bad Request | 通用「请求坏了」(语法/无法理解) | 能更具体时优先 401/403/404/409/422 |
| 401 | Unauthorized | 未认证(没登录 / Token 无效) | 名字像「未授权」,共识是「未证明身份」 |
| 403 | Forbidden | 已认证但无权限 | vs 401:有身份仍不准 |
| 404 | Not Found | 资源不存在;或故意隐藏存在性 | vs 403:有的安全策略对无权限也回 404 |
| 405 | Method Not Allowed | 路径在,方法不支持;常带 Allow |
路由漏注册常见 |
| 406 | Not Acceptable | 无法满足 Accept |
内容协商场景 |
| 408 | Request Timeout | 等客户端太久 | 少由业务手写 |
| 409 | Conflict | 状态冲突(版本、唯一键、重复创建) | vs 422:冲突偏「当前资源状态」 |
| 410 | Gone | 曾经有、现在永久没了 | 比 404 更「确认删除」 |
| 412 | Precondition Failed | If-Match 等前置条件失败 |
乐观锁 |
| 413 | Content Too Large | 体太大 | 网关也会发 |
| 415 | Unsupported Media Type | Content-Type 不支持 |
如只收 JSON 却来 XML |
| 422 | Unprocessable Content | 语义/校验失败(字段合法 JSON 但业务校验不过) | FastAPI/Pydantic 默认校验失败常用此码 |
| 429 | Too Many Requests | 限流;宜带 Retry-After |
监控勿一律当 5xx |
2.4 5xx — 服务端侧
| 码 | 名称 | 行业共识 | 客户端习惯 |
|---|---|---|---|
| 500 | Internal Server Error | 未处理异常、断言失败等 | 可有限重试;应修服务 |
| 501 | Not Implemented | 方法/功能未实现 | 少用;开发期可见 |
| 502 | Bad Gateway | 网关/代理上游坏响应 | 查上游 |
| 503 | Service Unavailable | 过载、维护;宜 Retry-After |
宜退避重试 |
| 504 | Gateway Timeout | 上游超时 | 查超时链 |
3. 方法 × 状态码:行业默认配对

| 方法 | 成功常见 | 失败常见 |
|---|---|---|
| GET | 200;条件命中 304 | 404;401/403 |
| POST 创建 | 201(+ Location) |
400/422;409 唯一冲突 |
| POST 动作/搜索 | 200;异步 202 | 同上 |
| PUT | 200/204;新建时 201 | 404/409/412/422 |
| PATCH | 200/204 | 404/409/412/422 |
| DELETE | 204 或 200 | 404(或幂等仍 204,见方法篇) |
| OPTIONS | 200/204 | CORS 失败在浏览器侧表现 |
与动词语义细节对照:02补。
4. 易混辨析(共识争议点)
| 对比 | 怎么选(共识) |
|---|---|
| 401 vs 403 | 没票 → 401;有票进不去 → 403 |
| 400 vs 422 | 报文级坏掉/框架难解析 → 400;JSON 已解析但字段校验失败 → 422(FastAPI 校验默认路径) |
| 404 vs 403 | 资源对你隐藏或不存在 → 常 404;明确「知道在但不许」→ 403 |
| 409 vs 422 | 「和当前资源状态打架」(版本、重复)→ 409;「字段本身不合法」→ 422 |
| 200 业务失败 | 不推荐:一律 200 再在 body 写 code≠0,会搞砸网关与通用客户端;业务码可作补充,不能取代 HTTP 码 |
| 500 vs 503 | 未知 bug → 500;已知过载/维护 → 503 |
关于「全用 200」:部分旧 RPC/网关风格仍存在;新 JSON API / OpenAPI 生态的主流共识是 HTTP 码表达结果类别。若历史包袱必须 body 业务码,至少在文档与监控规则里显式切开。
5. 较少手写但应认识
| 码 | 何时出现 |
|---|---|
| 100 Continue | 大上传前期望;多由协议栈处理 |
| 101 Switching Protocols | WebSocket 升级 |
| 206 Partial Content | 范围请求(视频/断点) |
| 418 | 彩蛋(I’m a teapot);勿用于生产语义 |
| 451 | 因法律原因不可用 |
6. FastAPI 落地(共识怎么写成代码)
1 | from fastapi import FastAPI, HTTPException, Response, status |
| 机制 | 用途 |
|---|---|
装饰器 status_code= |
成功默认码(OpenAPI 会展示) |
HTTPException |
预期内的 4xx/部分 5xx |
| 未捕获异常 | 通常 → 500(应有统一异常处理,见 04) |
| 请求体验证失败 | 默认 422 + 校验详情 |
统一错误响应形状(code / message / request_id)属于工程约定,与选对 HTTP 码正交——两者一起做。
7. 反模式清单
| # | 反模式 | 后果 | 改法 |
|---|---|---|---|
| 1 | 业务失败也 200 | 监控失真、客户端难写 | 4xx/5xx + body 详情 |
| 2 | 一律 500 表示「没找到」 | 触发错误重试与告警 | 404 |
| 3 | 鉴权失败用 403、匿名也 403 | 前端无法区分去登录还是无权限 | 匿名 401,无权限 403 |
| 4 | 创建成功回 200 且无 Location | 客户端不好发现新 URI | 201 + Location |
| 5 | 限流回 500 | 被当成故障扩容 | 429 + Retry-After |
| 6 | DELETE 成功硬塞大 JSON 却标 204 | 违反 204 无体约定 | 改 200 或真 204 |
8. 选型速查(决策树)
1 | 请求处理完了吗? |
9. 合书自测
- 401 与 403 的分工各是一句什么?
- FastAPI 默认请求体校验失败倾向哪个状态码?与 400 怎么划界?
POST创建成功为何偏好 201 而不是 200?- 为何不宜用 200 + body 错误码表达失败?
- 限流应回哪一个码?监控上为何不要记成 5xx?
10. 闪卡候选
| 正面 | 背面 |
|---|---|
| 2xx / 4xx / 5xx 责任? | 成功 / 客户端 / 服务端 |
| 201 关键场景? | 创建资源成功 |
| 202 含义? | 已受理、异步未完成 |
| 204 能有 body 吗? | 不应有 |
| 401 vs 403? | 未认证 vs 无权限 |
| 422 典型来源? | 语义/字段校验失败 |
| 429 是什么? | 限流 |
| 503 宜带什么头? | Retry-After |