告诉缓存一份已存应答何时还算新鲜的 HTTP 头。

缓存的新鲜度要对着时钟判断

响应经过另一个缓存,不代表自动获得一份全新的新鲜度额度。缓存必须计入交付路径上已经积累的年龄,再增加自己的本地停留时间。否则,每一层看起来都只缓存六十秒,串在一起却可能把旧内容直接复用远超源站预期的时间。判断新鲜度需要明确时间来源,不能只把配置中的秒数当成最终交付保证。 先算清年龄 Age 估计从响应生成或成功验证以来经过的秒数,其中包括缓存停留与网络传输。收到的 Age 是计算当前年龄的输入,不是在本地存放期间保持不变的计数器。Date 提供响应生成时间;把这些信息联系起来时,时钟同步和实际测得的请求、响应时刻都可能影响结果。只截取一组响应头,不能看到它随后在缓存里又停留了多久。 RFC 9111 给出两条年龄估计路径:接收时刻减去 Date,负数归零,得到表观年龄;收到的 Age 加响应延迟,得到校正年龄值。保守算法取两者较大值,再加本地停留时间。例如请求时刻为一百秒,接收为一百零二秒,Date 为九十五秒,收到的 Age 为十秒,当前时刻为一百零七秒,表观年龄是七秒,校正值是十二秒,当前年龄最终为十七秒。只读原始 Age 就漏算了七秒。 新鲜度寿命也有优先顺序。共享缓存存在 s-maxage 时先用它,否则 max-age 优先于 Expires 减 Date;私有缓存忽略 s-maxage。没有显式过期信息时,在允许的条件下可能使用启发式寿命,但并不存在统一固定时长。只有适用的新鲜度寿命严格大于当前年龄,响应才是新鲜的;恰好相等时已经到达陈旧边界,而不是再多送一次的许可。 坏掉的样子 新鲜不代表适合任意请求。存储许可、网址与 Vary 匹配、验证要求仍然有效。即使寿命设得很长,no-cache 也要求复用前验证。ETag 是验证器,不是免于询问源站的许可。成功重验证可以更新保存的元数据而不重新传正文,但仅仅从另一个缓存收到响应,不能把年龄清零,否则每经过一层就会错误地延长直接复用期限。 提供陈旧响应需要另外的许可,不能把源站故障当成自动授权。must-revalidate 禁止过期后未经成功验证就复用,即使网络断开也不例外。stale-while-revalidate 可以允许在有界的陈旧窗口内一边返回旧内容、一边验证,但仍受适用限制约束,也不会把旧内容重新变成新鲜内容。RFC 9111 已废弃 Warning 字段,因此没有旧式 Warning: 110 不能作为新鲜度证据。 ...

十二月 3, 2027 · 2 分钟 · XB Field Notes