Pragma 是 HTTP/1.0 的遗留字段,只有一个值有意义:no-cache。
它的存在只是为了照顾老到看不懂 Cache-Control 的中间件。
上一节讲时间,这一节讲一个几乎已经没用的字段。但它天天出现在老代码里,所以必须认得。
一、它的全部历史
HTTP/1.0 时代没有 Cache-Control,只有 Pragma: no-cache 这一个开关。
HTTP/1.1 引入 Cache-Control 之后,Pragma 就被保留了,但规范明确说它「只作为向后兼容而存在」。
所以这个字段只有一种用法是对的:和 Cache-Control: no-cache 一起发,
让那些只认 1.0 的老中间件也照办。
其他所有值都是未定义的。
写 Pragma: no-store 或者 Pragma: max-age=0 不会有任何效果——它们不在规范里。
二、两个都发的时候听谁的
Demo 试了四种组合,结论很清楚:
| 发的东西 | 实际判定 |
|---|---|
| 只有 Pragma: no-cache | 没有 Cache-Control,退回按 Pragma 处理 |
| 只有 Cache-Control: no-cache | 按 Cache-Control:每次都验证 |
| 两个都是 no-cache | 按 Cache-Control:每次都验证 |
| Pragma: no-cache 加 Cache-Control: max-age=600 | Pragma 被忽略,按 max-age 缓存 |
最后一行是关键:只要出现了 Cache-Control,Pragma 就完全失效,
哪怕 Cache-Control 里根本没有 no-cache。
这条规矩很多人不知道,
于是写出 Pragma: no-cache 加 Cache-Control: max-age=3600 这种自相矛盾的组合,
以为前者能兜住后者,实际完全无效。
三、为什么今天还在用它
因为老系统多。2010 年前后的大量框架、代理、甚至一些企业内网的网关,只认 Pragma。
所以你会看到「双保险」的写法:两条都发,一条给新设备,一条给老设备。
这在过渡期是合理的,但新项目不该再发 Pragma。
读代码时要有这个意识:看到 Pragma 就知道这段代码要么很老,要么在兼容很老的客户端。
它是个时间戳,标记着这段代码的年龄。
四、动手 Demo:四种组合,看谁说了算
分四次发:只有 Pragma、只有 Cache-Control、两个都发、以及 Pragma 配一个相反的 max-age, 看服务端的判定怎么变。
cc = hd.get(u'cache-control', u'')
pg = hd.get(u'pragma', u'')
if cc:
if u'no-cache' in cc.lower():
verdict = u'按 Cache-Control 处理:每次都验证'
else:
verdict = u'有 Cache-Control(%s),Pragma 被忽略' % cc
elif u'no-cache' in pg.lower():
verdict = u'没有 Cache-Control,退回按 HTTP/1.0 的 Pragma 处理'
else:
verdict = u'没有缓存指令'
实跑输出:
--------------------------------------------------------------------
Pragma: no-cache 是个历史包袱
--------------------------------------------------------------------
【只发 Pragma: no-cache】
服务端收到的首部 host | pragma
实际判定 没有 Cache-Control,退回按 HTTP/1.0 的 Pragma 处理
【只发 Cache-Control: no-cache】
服务端收到的首部 cache-control | host
实际判定 按 Cache-Control 处理:每次都验证
【两个都发】
服务端收到的首部 cache-control | host | pragma
实际判定 按 Cache-Control 处理:每次都验证
【发 Pragma: no-cache 加 max-age】
服务端收到的首部 cache-control | host | pragma
实际判定 有 Cache-Control(max-age=600),Pragma 被忽略
Pragma 是 HTTP/1.0 的产物,只有一个值有意义:no-cache。
它的存在只为了一个目的:让老到看不懂 Cache-Control 的中间件也照办。
HTTP/1.1 里如果两个都出现,按标准 Cache-Control 赢,Pragma 被忽略。
所以今天写新代码不该再发 Pragma,但读代码时要认得它——
老系统里到处是「Pragma: no-cache 加 Cache-Control: no-cache」的双保险写法。
只有 Pragma: no-cache 时,服务端拿不到任何 Cache-Control,
只能退回按 1.0 的规矩办——这是它唯一还有用的场合。
只有 Cache-Control: no-cache 时,正常判定为「每次都验证」。
两个都发,结果和只有 Cache-Control 一样。Pragma 是冗余的,但不会造成错误。
最后一组最能说明问题:Pragma: no-cache 配 Cache-Control: max-age=600,
判定是「有 Cache-Control,Pragma 被忽略」。那 600 秒的缓存照旧生效——Pragma 一点用都没起。
30 秒实验
- 把最后一组反过来:
Cache-Control: max-age=0配Pragma: no-cache,看判定变不变。 - 发一个
Pragma: no-store,看服务端认不认这个值。 - 想一想:为什么「双保险」这种写法在过渡期之后应该被清理掉?
常见误区
- 「
Pragma是Cache-Control的别名」——只有no-cache一个值重叠。 - 「两个都发就以 Pragma 为强」——正好相反,Cache-Control 赢。
- 「
Pragma: no-store能禁止存储」——那个值不存在,没有效果。
自测三问(点开对答案)
1. `Pragma` 只有一个有意义的值是什么? —— `no-cache`。其他值都是未定义的。 2. 同时出现 `Pragma: no-cache` 和 `Cache-Control: max-age=600`,听谁? —— 听 `Cache-Control`。只要它出现,`Pragma` 就完全失效。 3. 为什么新项目不该再发 `Pragma`? —— 它只为兼容 HTTP/1.0 的老中间件而存在,现代实现都认 `Cache-Control`。遗留字段说完了。下一个字段解决一个真问题:正文发完了才知道的信息往哪儿放。
- ☐ (本节完,下一节 6.3.5 Trailer)