📘 第六章 HTTP首部
📄 一句话概括

Warning 用来在报文里写一句「这份东西有问题」——比如「这是过期的副本」「内容被中间件改过」。 格式是三段:三位码、可选代理名、引号括起来的说明。

📝 本节和前面几节的关系

这是通用首部的最后一个,也是本章第一个「已经废弃」的字段。学它的价值在于认得出,而不是用得上。

一、三段格式

一个 Warning 长这样:110 gw1 "Response is Stale"。 三段分别是:三位警告码、发出警告的代理名(可省略)、双引号括起来的说明文字。 说明文字必须用双引号。 这是 HTTP/1.1 里少见的「值里有引号」的字段,所以解析时不能简单按逗号或空格切。 一个响应里可以有多条 Warning,写作多行或者用逗号连接。Demo 里那个 /multi 请求就收到了两条。

二、警告码分两段

1xx 开头说的是「这份缓存有问题」:110 过期、111 验证失败、112 离线、113 有效期是猜的、 199 杂项。 2xx 开头说的是「内容被改过」:214 表示中间件做了转换(压缩、转码、格式调整), 299 是长期有效的杂项。 这两类的区别很重要:1xx 的问题会随着重新验证而消失, 2xx 的问题会一直存在——因为内容真的和源服务器不一样了。 Demo 的输出里把这七个码都列了出来,配英文原文和中文解释。

三、为什么它被废弃了

2015 年的 RFC 7234 把 Warning 标记为废弃(obsolete)。原因是它实现了二十年,几乎没人正确处理。 具体表现是:中间件会生成它,客户端会忽略它,于是这些信息既没人看,又白占了首部字节。 同样的信息现在有更实用的传递方式: 缓存状态可以放在自定义首部里(比如 CDN 厂商常加的 X-Cache: HIT),或者干脆只写进日志, 给运维看而不是给客户端看。 所以读这一节的心态应该是:看到 Warning 要知道它什么意思,但自己不要再生成它。 这和上一节 Pragma 的处理方式一样——都是「认得出、不该用」的历史字段。

四、动手 Demo:三种响应里的警告条数

三个路径:一个干净、一个带过期警告、一个带两条警告。 各请求一次,把 Warning 首部原样打出来,再列出七个警告码的含义。

if path == u'/stale':
    return reply(u'HTTP/1.1 200 OK',
                 [(u'Age', u'900'),
                  (u'Warning', u'110 - "Response is Stale"')], body)
if path == u'/multi':
    return reply(u'HTTP/1.1 200 OK',
                 [(u'Warning', u'110 gw1 "Response is Stale"'),
                  (u'Warning', u'214 proxy2 "Transformation Applied"')], body)

实跑输出:

--------------------------------------------------------------------
Warning:把「这份东西有问题」写在报文里
--------------------------------------------------------------------
  /clean                     HTTP/1.1 200 OK | 警告 0 条 | 响应 107 字节

  /stale                     HTTP/1.1 200 OK | 警告 1 条 | 响应 160 字节
                             Warning: 110 - "Response is Stale"

  /multi                     HTTP/1.1 200 OK | 警告 2 条 | 响应 195 字节
                             Warning: 110 gw1 "Response is Stale"
                             Warning: 214 proxy2 "Transformation Applied"

  警告码的分段:
    110                      Response is Stale                 缓存给的副本已经过期
    111                      Revalidation Failed               想去验证但连不上源服务器
    112                      Disconnected Operation            缓存处于离线模式
    113                      Heuristic Expiration              有效期是猜的,超过 24 小时
    199                      Miscellaneous Warning             杂项警告
    214                      Transformation Applied            中间件改过内容(比如压缩、转码)
    299                      Miscellaneous Persistent Warning  长期有效的杂项警告

  Warning 的格式是三段:三位码、可选的代理名、引号括起来的说明文字。
  1xx 开头的是「这份缓存有问题」,2xx 开头的是「内容被改过」。
  它在 HTTP/1.1 里没被广泛实现,实战中很少见到。
  2015 年的 RFC 7234 已经把 Warning 标记为废弃,
  现在这些信息更多靠自定义首部或日志来传达。

/clean:0 条警告,状态 200。 /stale:1 条,Warning: 110 - "Response is Stale", 配着 Age: 900——说明这份副本已经躺了十五分钟。 /multi:2 条,一条是过期的 110,一条是内容被改过的 214。两条可以同时存在。 注意 110 那条里代理名位置写的是 -:这是「不知道是谁发的」的写法。 第二组的 gw1 和 proxy2 则是具体的代理名。 七个码列出来是 110/111/112/113/199/214/299。前五个是 1xx,后两个是 2xx。

30 秒实验

  1. 给 /multi 再加一条 299,看客户端能不能正确读出三条。
  2. 把说明文字的双引号去掉,看解析会不会出错(规范要求必须有)。
  3. 想一想:既然客户端都忽略它,为什么当年还要设计这么一套编码?

常见误区

  1. 「Warning 是错误码」——它是警告,状态码仍然是 200。
  2. 「说明文字不用引号」——规范要求用双引号括起来。
  3. 「Warning 还在广泛使用」——2015 年就被标记废弃了。
自测三问(点开对答案) 1. `Warning` 的三段格式是什么? —— 三位警告码、可选的代理名、双引号括起来的说明文字。 2. 1xx 和 2xx 开头的警告码有什么区别? —— 1xx 说的是缓存有问题(会随重新验证消失),2xx 说的是内容被改过(一直存在)。 3. `Warning` 为什么被废弃? —— 实现了二十年几乎没人正确处理,中间件生成、客户端忽略,白占字节。

通用首部九个讲完了。下一节换方向:客户端能发的那 19 个请求首部。

相关笔记