📘 第四章 返回结果的HTTP状态码
📄 一句话概括

状态码是三位数字,第一位定责任方:4 开头是你的锅,5 开头是我的锅。 后两位只在本家族内有意义。

📝 本节和前面几节的关系

前三章拆完了报文。 从这一节起看响应的第一行——那三个数字是运维排查的第一手线索,也是监控告警的唯一依据。

一、五个家族,一句话分工

家族 含义 谁该动手
1XX 信息,请求已收到,继续 客户端等
2XX 成功 没人需要动手
3XX 重定向,还要再走一步 客户端跟着走
4XX 客户端错,改请求才有用 客户端
5XX 服务端错,改请求没用 服务端
这条分工比记住具体哪个码重要得多。
看到 4XX 先去查请求(参数、认证、路径),
看到 5XX 先去查服务端日志——方向对了,一半时间就省下了。
后两位没有跨家族规律。
不要以为「400 和 500 差不多」——一个是语法错,一个是内部崩溃,处理方式完全相反。

二、原因短语是可以扔掉的

HTTP/1.1 200 OK 里的 OK 叫原因短语(reason-phrase),纯粹给人看,程序只认那个数字。 你可以写 200 一切正常,甚至留空,客户端照样工作。HTTP/2 干脆把它删了——状态行只有版本和数字。 这也是排查时的一个提醒:日志里看到奇怪的原因短语,说明中间某个设备改过它, 而那个设备可能也改了别的东西。

三、1XX 几乎见不到

100 Continue 是唯一还有存在感的:客户端要发大正文时,先发首部问一句「你收吗」, 服务端回 100 再发正文,避免白传。 101 Switching Protocols 用在 WebSocket 握手:服务端同意把这条连接升级成别的协议(9.3 节)。 这两个都出现在「请求还没结束」的阶段,抓包里夹在中间,不熟悉的人常常当成异常。

四、动手 Demo:把常见状态码按家族数一遍

把 26 个常见状态码按「百位」分组统计,看每个家族有多少个、分别是哪些。数字全部由代码算。

codes = [(100, u'Continue'), (200, u'OK'), (301, u'Moved Permanently'),
         (404, u'Not Found'), (500, u'Internal Server Error'), ...]
fam = {}
for c, name in codes:
    fam.setdefault(c // 100, []).append((c, name))

实跑输出:

--------------------------------------------------------------------
状态码是一位数分家族的三位数字
--------------------------------------------------------------------
  统计的码总数               26 个
  1XX 信息(请求已收到,继续) 2 个
  2XX 成功                   4 个
  3XX 重定向(还要再走一步) 6 个
  4XX 客户端错(改请求才有用) 9 个
  5XX 服务端错(改请求也没用) 5 个

  1XX:100、101
  2XX:200、201、204、206
  3XX:301、302、303、304、307、308
  4XX:400、401、403、404、405、408、413、416、429
  5XX:500、501、502、503、504

  第一位的作用               判断责任方:4 是客户端的锅,5 是服务端的锅
  后两位                     只在该家族内有意义,没有跨家族规律
  原因短语                   纯给人看,程序只认数字(HTTP/2 已删除)
  记住「第一位定责任方」这一条,排查就有一半方向了:
  看到 4XX 先查自己的请求,看到 5XX 先查服务端日志。

统计的码总数 26 个,分成 2/4/6/9/5 五组。4XX 最多,因为客户端能犯的错花样最多。 第一位的作用 判断责任方——这一行是整节的结论。把它写进监控规则的备注里,值班的人会感谢你。 原因短语 纯给人看,程序只认数字(HTTP/2 已删除)。 这一条在写客户端时很关键:别按短语判断,一定按码判断。

30 秒实验

  1. 把 418(I'm a teapot)加进列表,看它落在哪个家族。
  2. 列出你自己项目里用到的状态码,看看有没有「全用 200」的接口。
  3. 查一下 499 这个码——它不在任何标准里,是 Nginx 自己加的。

常见误区

  1. 「状态码越具体越好」——用错家族比用错具体码更糟。业务失败回 200 是最大的坑。
  2. 「原因短语可以当判断依据」——程序只认数字,短语随便改。
  3. 「所有错误都应该回 500」——400 和 500 的责任方完全不同,混用会让排查方向全错。
自测三问(点开对答案) 1. 状态码第一位的作用是什么? —— 判断责任方:4XX 客户端、5XX 服务端、3XX 要再走一步、2XX 成功。 2. 原因短语能用来做判断吗? —— 不能。程序只认数字,短语是纯文本说明,HTTP/2 已经把它删了。 3. 1XX 出现在什么时候? —— 请求还没结束时,比如 `100 Continue` 表示「可以继续发正文」。

家族分清了。接下来逐个看:先看最熟悉的 2XX。

相关笔记