FastAPI-02补2.HTTP状态码行业共识手册

定位02补 讲「动词合同」;本文讲「结果合同」——状态码。规范底本为 RFC 9110;文中「行业共识」指 REST/JSON API 里被网关、客户端库、监控广泛默认的用法,不是业务法条。最终响应仍由你的 handler 决定,但选错码会误导重试、告警与缓存。


0. 先记住:状态码是给机器看的合同

角色 靠状态码做什么
浏览器 / 客户端 SDK 是否重试、是否跳转、是否弹登录
反向代理 / CDN 是否缓存、是否熔断上游
监控 / SLO 5xx 算故障;4xx 常算客户端问题(需按业务再切)
一眼分「谁的锅」

费曼一句:方法说「我想干什么」,状态码说「这件事结局如何、错在哪一侧」。body 里的 { "error": "..." } 是给人看的细节,不能代替状态码。

图 A 状态码五大家族

段末注释HTTP 状态码(status code)是响应起始行中的三位数字,表示请求处理结果的类别与具体含义;后文直接写数字(如 404)。


1. 五大家族(行业第一刀)

范围 共识含义 API 日常频率
1xx 100–199 中间态 / 协议控制(继续、切换协议) 低(框架/协议层居多)
2xx 200–299 成功
3xx 300–399 重定向(去别处拿结果) 中(短链、www、HTTPS)
4xx 400–499 客户端错(请求本身有问题)
5xx 500–599 服务端错(服务器或上游挂了) 高(告警主战场)

粗分责任:

1
2
3
2xx → 办成了(或按约定受理了)
4xx → 请改请求再来(鉴权、参数、路径、冲突…)
5xx → 服务侧故障(可重试与否看具体码)

2. API 必会清单(按共识强度)

下列为 JSON API / FastAPI 项目里几乎人人默认的集合;冷门码放 §5。

图 B 2xx 与常见 4xx

2.1 2xx — 成功

名称(常称) 行业共识用法 典型搭配 局限 / 注意
200 OK 通用成功;GET/PUT/PATCH/动作型 POST 有正文 读资源、更新后回写表示 别用 200 包装业务失败(反模式)
201 Created 新建成功;常带 Location 指向新资源 POST 集合创建;有时 PUT 新建 应真的创建了资源;仅「受理」用 202
202 Accepted 已受理、尚未做完(异步) 长任务、入队 需另提供查询状态的接口
204 No Content 成功且无响应体 DELETEPUT/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. 方法 × 状态码:行业默认配对

图 C 方法与状态码配对示意

方法 成功常见 失败常见
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from fastapi import FastAPI, HTTPException, Response, status
from fastapi.responses import JSONResponse
from pydantic import BaseModel

app = FastAPI()


class ItemCreate(BaseModel):
name: str


@app.post("/items", status_code=status.HTTP_201_CREATED)
async def create_item(body: ItemCreate):
new_id = 42
return JSONResponse(
status_code=status.HTTP_201_CREATED,
content={"id": new_id, "name": body.name},
headers={"Location": f"/items/{new_id}"},
)


@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_item(item_id: int):
return Response(status_code=status.HTTP_204_NO_CONTENT)


@app.get("/items/{item_id}")
async def get_item(item_id: int):
if item_id < 0:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="invalid id")
if item_id == 404:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="item not found")
return {"id": item_id}
机制 用途
装饰器 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
请求处理完了吗?
├─ 还在协议中间态 → 1xx(少手写)
├─ 成功
│ ├─ 新建了资源 → 201
│ ├─ 已受理未完成 → 202
│ ├─ 成功无正文 → 204
│ └─ 其它成功 → 200
├─ 要客户端换 URI → 3xx(注意是否保留方法)
├─ 客户端问题
│ ├─ 未登录/Token 坏 → 401
│ ├─ 无权限 → 403
│ ├─ 没有这个资源 → 404
│ ├─ 方法不对 → 405
│ ├─ 状态冲突 → 409
│ ├─ 字段校验不过 → 422
│ ├─ 限流 → 429
│ └─ 其它坏请求 → 400
└─ 服务端问题
├─ 过载/维护 → 503
├─ 网关上游超时 → 504
├─ 网关上游坏 → 502
└─ 未知错误 → 500

9. 合书自测

  1. 401 与 403 的分工各是一句什么?
  2. FastAPI 默认请求体校验失败倾向哪个状态码?与 400 怎么划界?
  3. POST 创建成功为何偏好 201 而不是 200?
  4. 为何不宜用 200 + body 错误码表达失败?
  5. 限流应回哪一个码?监控上为何不要记成 5xx?

10. 闪卡候选

正面 背面
2xx / 4xx / 5xx 责任? 成功 / 客户端 / 服务端
201 关键场景? 创建资源成功
202 含义? 已受理、异步未完成
204 能有 body 吗? 不应有
401 vs 403? 未认证 vs 无权限
422 典型来源? 语义/字段校验失败
429 是什么? 限流
503 宜带什么头? Retry-After

小结

  • 状态码是行业可机读的结果合同;实现可乱写,但乱写会惩罚协作方。
  • API 日常:200/201/202/204 + 400/401/403/404/405/409/422/429 + 500/502/503/504 覆盖绝大多数场景。
  • 02补 方法 成对记忆;异常统一出口见 04
-------------本文结束感谢您的阅读-------------