摘要
- RFC 9111 建议带有
must-understand的响应同时带上no-store。不认识新指令的旧缓存会忽略前者,却仍能按后者采取保守行为。 - “理解状态码”不是能解析三个数字,也不是能识别指令名称,而是既认识该状态码,又落实其规范规定的全部缓存相关行为。
- 符合条件后忽略
no-store,只移除一项禁止。请求方法、授权、共享缓存限制、可缓存性、新鲜度与后续复用仍要分别满足;这组指令也不承诺隐私。
升级机制中不显眼的那一半
设想两台缓存都收到:Cache-Control: must-understand, no-store。
第一台部署较早,不认识 must-understand。HTTP 对扩展指令的规则要求它忽略未知项。它随后读到自己认识的 no-store,于是拒绝存储响应。
第二台实现了 must-understand。但这还不够。它必须认识本次响应的状态码,并且已经实现该状态码规范中的全部缓存要求。只有满足这项条件,RFC 9111 才建议它忽略随行的 no-store,再按其余缓存规则判断响应是否可存。
两条路径共同解决了协议升级最现实的问题:网络中的参与者不会在同一时刻全部换代。源站不必先知道路径上每台缓存的版本。旧实现获得一个早已理解的保守指令;新实现则凭本地能力证明进入较宽的分支。
如果操作手册只摘出 must-understand,这套安排就会被误读。它的名字像一项对所有中间层都有效的命令,可一个从未实现它的缓存恰恰必须将其忽略。没有 no-store,旧缓存就收不到本应负责兜底的信号。真正的发布单位是指令对,真正的控制点是进入新分支所需的证据。
“理解”描述行为,而不是词汇表
RFC 9111 对“理解”给出了严格定义:缓存要认识请求方法或响应状态码,同时实现规范为其规定的全部缓存相关行为。
解析器能够读取三位数字,只证明语法通过;界面能显示状态名称,只证明有一张映射表;HTTP 客户端能把未知状态按同一类别处理,只证明具备通用回退。这些都没有说明缓存引擎执行了该状态码特有的存储规则。
规范之间的对照说明了这种差异。RFC 6585 规定,428、429、431 与 511 响应不得被缓存存储。RFC 7538 则把 308 Permanent Redirect 定义为默认可缓存,除非请求方法语义或明确的缓存控制另有规定。这些例子不是完整清单,但足以说明状态码可能带来相反的缓存结果。
假如某产品会把 429 显示为“Too Many Requests”,却把响应当作普通对象保存,它认识数值,却没有按 RFC 9111 所要求的意义理解它。类似地,仅检查 must-understand 能否被解析的功能开关,测到的是词法支持,而非状态行为的完整实现。
一份可信的运行记录至少要分开五件事:响应状态码;是否认识该状态码;是否实现其缓存要求;是否实现 must-understand;以及撤去例外后其余存储和复用条件是否通过。把它们压成一个“支持”字段,就是让条件性互操作退化为自我认证。
旧指令不是重复,而是退路
缓存必须忽略不认识的 Cache-Control 指令,否则任何扩展都可能使已部署软件失效。RFC 9111 因而给行为型扩展规定了一种组合方式:新指令与旧指令一同发送;不认识新指令的实现采用旧行为,认识新指令的实现知道新规则如何修改旧要求。
在这里,no-store 正是旧行为。它并不与 must-understand 自相矛盾,而是定义最安全的默认路径。旧缓存知道停下;符合条件的新缓存知道在什么狭窄情形下可以移开这道限制。
省略它会改变升级结果。只有 must-understand 时,旧缓存将忽略唯一收到的新信号。它或许会因为其他条件而不存储,但那不再是这套兼容设计提供的保障。
RFC 9111 对“应同时带上 no-store”以及“符合条件的缓存应忽略它”都使用 SHOULD。这个规范词不是随意建议,也不是无条件 MUST。偏离可以有技术理由,却必须讲得清楚;节省几个字节并不能回答旧实现会怎样处理。
移去一道禁止,不等于满足全部条件
“忽略 no-store”常被误写成“允许缓存”。两者不是同一判断。
RFC 9111 第 3 节列出的其他存储条件仍然存在:请求方法必须允许;响应状态必须是最终状态;若为特定状态或存在 must-understand,缓存必须理解状态码;授权与共享缓存规则可能适用;共享缓存仍要服从 private;响应还需要明确控制或状态默认规则提供可缓存依据。
存储之后还有复用。一个已保存响应只有在请求匹配,并且它仍新鲜、已成功验证或符合陈旧响应许可时,才可用于回答后续请求。must-understand 不会令对象自动新鲜,不会完成验证,也不会修正跨用户的错误缓存键。
因此可观测性应当记录一条决策链,而不是 must_understand=true:采用了哪个状态码定义,什么版本和测试证明实现其行为,两条指令是否都在,其他存储条件如何,最终是否写入,以及日后是否复用。只有这样,条件例外才不会在报表里变成永久豁免。
注册表提供坐标,不提供合格证
IANA 的 HTTP 缓存指令注册表分别列出 must-understand 与 no-store,状态码注册表则列出数值、名称与定义文档。它们提供共同坐标,避免命名冲突,并把实现者带到正确的规范。
注册并不认证软件。一个词出现在 IANA 表中,不代表某个二进制已经实现;一个状态码拥有正式条目,也不代表某台缓存落实了它的专门要求。即使一个状态的测试已经通过,也不能推断未来新增状态自动得到支持。
因此,状态行为是实际依赖。模块版本、启用范围、规范版本和测试结果要随能力声明一起保存。must-understand 提供了在协议层询问这项能力的分支点,却不能代替实施证据。
RFC 9111 的变更说明指出,该指令被引入后,缓存通常不必理解新响应状态码的语义,除非响应带有它。这让源站可以表示“本响应的状态特有规则很重要”。源站不能借此远程宣布一台未知缓存已经胜任。
这不是隐私或保密承诺
RFC 9111 明确提醒,no-store 不是可靠或充分的隐私机制。恶意或受控缓存可能不识别、不服从,通信网络也可能被窃听。与 must-understand 配对不会扩大它的安全承诺。
两条指令也不决定谁获准接收响应,不保证共享缓存正确隔离用户,不提供传输保密,更不说明数据落盘后如何保护。若把它当作数据分类印章,反而会掩盖真正负责访问、加密和留存的控制。
本文没有测试任何缓存产品,也没有测量支持率、存储泄漏或事故频率。所有路径都只是依据公开规范构造的分析情形。
来源与证据边界
- RFC 9111:HTTP Caching
- RFC 9111 发布记录
- RFC 9110:HTTP Semantics
- RFC 7234:HTTP/1.1 Caching
- IANA HTTP 缓存指令注册表
- IANA HTTP 状态码注册表
- RFC 9111 勘误
- RFC 5861:陈旧内容缓存控制扩展
- RFC 9211:Cache-Status
- RFC 6585:附加 HTTP 状态码
- RFC 7538:308 Permanent Redirect
- RFC 8174:规范关键词大小写的含义
- 卢恒:最小初始规范、本地化未来决策与自愿采用
- 卢恒:The Policy Mirror
注册表与勘误状态只代表研究截止时的快照。来源支持协议语义和治理推论,不构成产品普遍支持或合规性的证据。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
