Skip to content

HTTP 状态码详解

本章导读:状态码是服务器对"这次请求发生了什么"的官方判决(RFC 9110 §15 定义了完整注册表)。本章按类别精讲每个状态码的语义、义务性头部、适用场景与常见误用,并给出 CRUD 场景的速查矩阵。

0. 阅读须知

  • 状态码是三元组:数字 + 原因短语 + 语义规范(原因短语仅为人读,客户端只看数字)。
  • "服务器 SHOULD/MUST/MUST NOT"是 RFC 2119 关键词:MUST=义务,SHOULD=默认应做(有正当理由可不做),MAY=可选。
  • 自定义状态码只能使用 600~999?——不推荐任何自定义码:既有客户端/代理可能拒绝未知码;业务细分请用 problem+jsontype 错误码(见上一章)。

1. 1xx 信息性

名称说明
100Continue客户端发大 body 前用 Expect: 100-continue 试探,服务器说"可以继续发"
101Switching Protocols协议切换(WebSocket 握手 Upgrade: websocket 就走这个)
103Early Hints提前返回 Link 预加载提示(配合 200 使用)

API 设计中 1xx 多由框架/网关自动处理,了解即可。

2. 2xx 成功

200 OK

请求成功,body 含结果表示。GET/PUT/PATCH/POST 的通用成功码。避免:所有响应都 200——错误、创建、无内容场景都有更精确的码。

201 Created

POST 创建新资源成功(或 PUT upsert 创建)。

  • 义务:Location 头指向新资源 URI(SHOULD);
  • body 可返回新资源表示(方便客户端免去二次 GET),也可只给 Location
  • 异步创建(尚在处理)用 202 而不是 201。

202 Accepted

请求已受理但处理未完成——异步作业入口:

http
POST /v1/videos
HTTP/1.1 202 Accepted
Location: /v1/jobs/88            ← 用作业资源跟踪进度
Content-Location: /v1/videos/9
Link: </v1/jobs/88>; rel="monitor"

204 No Content

成功,无 body(响应必须无 body)。典型:DELETE 成功、PUT/PATCH 成功且不需要返回新表示、OPTIONS 预检。

  • 204 ≠ 失败:"没内容"是成功语义;
  • 客户端收到 204 应保留当前缓存表示之外的认知:资源已变更(缓存要失效,见缓存章)。

206 Partial Content

范围请求成功(Range: bytes=0-1023Content-Range: bytes 0-1023/8665),音视频拖动、断点续传的机制核心。若 Range 不合法返回 416 Range Not Satisfiable

其它:203 Non-Authoritative Information(代理改写表示)、205 Reset Content(表单场景命令客户端重置输入)——API 罕见。

3. 3xx 重定向与条件

名称方法是否可变使用要点
301Moved PermanentlyPOST→GET 可能永久迁移,客户端应改存新 URI;带 Location
302Found同上临时跳转;不改变客户端已存 URI
303See Other强制变 GETPOST/PUT 成功后跳到结果页(PRG 模式:Post/Redirect/Get)
304Not Modified条件请求命中,缓存生效;无 body
307Temporary Redirect不变临时跳转且保持方法/body
308Permanent Redirect不变永久迁移且保持方法(REST 资源改名优先 308)

3xx 设计守则:

  • 能路由兼容就不要重定向(多一次往返 + 安全策略复杂化);重定向目标尽量同域。
  • 304 Not Modified 是缓存系统自动协商的产物(If-None-Match/If-Modified-Since 命中),API 代码通常不手动返回。
  • 301/302 的历史包袱(方法可能被改成 GET)是 307/308 存在的唯一理由——API 迁移请用 308

4. 4xx 客户端错误

认证授权三连

400 Bad Request            请求本身有问题(语法/参数),改了再发
401 Unauthorized           身份没证明 → 必须带 WWW-Authenticate(RFC 7235)
403 Forbidden              身份知道了,但禁止操作;重试无意义(除非改角色)
405 Method Not Allowed     方法不对 → 必须带 Allow 头
406 Not Acceptable         Accept 协商失败
404 vs 403:敏感资源对无权限者伪装 404(防枚举),团队定策略

状态与并发的码

场景关键义务/说明
409 Conflict与当前资源状态冲突:唯一约束、状态机非法迁移、版本冲突(无 ETag 体系时)body 说明冲突原因;与 412 区分:412=预条件头失败,409=业务规则冲突
410 Gone资源永久删除/端点已下线比 404 多一层"别再来"语义;SEO 也靠它
411 Length Required需要 Content-Length罕见(chunked 上传策略)
412 Precondition FailedIf-Match/If-Unmodified-Since 不满足乐观锁的标准失败响应
413 Content Too Largebody 超限可带 Retry-After;上传 API 应告知上限
414 URI Too Long请求行超限长查询串改 POST 提交
415 Unsupported Media TypeContent-Type 不对例:发 text/plain 但只收 JSON
416 Range Not SatisfiableRange 越界Content-Range: */实际大小
422 Unprocessable Content语法正确语义失败校验错误的头号归处(RFC 9110 更名自 Unprocessable Entity)
425 Too Early请求可能重放(TLS 0-RTT)了解
428 Precondition Required要求带条件头但没带(RFC 6585)强制乐观锁的接口用它
429 Too Many Requests限流(RFC 6585)必须带 Retry-After;建议 RateLimit 三头

4xx 的缓存与监控注意

4xx/5xx 响应默认不可缓存(除非显式 Cache-Control);监控告警统计应以 4xx 比例为客户端健康度指标,5xx 比例为服务健康度指标。

5. 5xx 服务器错误

场景要点
500 Internal Server Error未分类异常兜底码;频繁出现 = 缺陷清单没做好映射
501 Not Implemented方法不被支持(比 405 更"诚实")一般还是用 405;501 指"整个方法未实现"
502 Bad Gateway网关/代理的上游返回无效响应微服务链路常见,排查看上游
503 Service Unavailable过载/维护,暂时性应带 Retry-After;LB 摘除节点后返回它
504 Gateway Timeout上游超时与 502 区分:超时 vs 无效响应
505 HTTP Version Not Supported版本不支持罕见

5xx 响应绝不携带堆栈/SQL/内部配置;ServerX-Powered-By 等头部做剥离处理(详见安全章)。

6. CRUD 场景速查矩阵

操作成功(有 body)成功(无 body)失败常见码
GET 单个200404、401、403、410(曾存在)
GET 集合200(空列表也是 200)400(非法过滤参数)、416(范围)
POST 创建201(+Location)400、401、403、409(重复)、422(校验)、429
PUT 替换200 或 204204400、404、401、403、409、412(版本不符)、422
PATCH 修改200 或 204204同 PUT;415(补丁格式错)
DELETE 删除200(返回被删资源)204404、401、403、409(有依赖)、410(已永久删)
异步创建202(+Location→作业)401、429
条件 GET 缓存命中304

7. 本章小结

  • 状态码选择三问:成功了该给哪个 2xx?客户端能修吗(4xx)还是服务器能修(5xx)?有没有 MUST 级头部义务(401/405/409/412/429)?
  • 重定向家族:308 保方法、303 转 GET、304 给缓存——别再用 302 走天下。
  • 422/409/412 是"高级感"三码:会用它们表达校验、冲突、并发,是 API 设计成熟的标志。

8. 下一步

进阶篇开始。先解决"协商"——多格式/多语言/多版本如何选 → 内容协商