s-maxage:被漏掉最多的一行缓存配置
只写 max-age 会把边缘缓存和浏览器缓存绑在同一个时长上。而这两者合适的时长几乎从来不同——浏览器缓存发出去就召不回,边缘缓存随时可刷。
6 分钟缓存与命中

要点
用 s-maxage 放长边缘 TTL、用 max-age 收短浏览器 TTL,既提高命中率又保留随时刷新的能力。
两种缓存的根本不对称
边缘缓存和浏览器缓存看起来是同一件事的两级,实际有一个决定性差别:边缘缓存你能主动刷,浏览器缓存你不能。
发现线上文件有问题时,边缘副本可以��控��台里一键刷新,几十秒内全网生效。但已经进了用户浏览器的副本,在 max-age 到期前无论如何都不会再来问你——哪怕你已经修好了。
这个不对称的后果
max-age=2592000(30 天)意味着一次错误发布,最坏情况要在部分用户那里挂 30 天。而 s-maxage=2592000 配 max-age=3600 能拿到几乎一样的命中率,事故窗口却只有 1 小时。
两条指令怎么配合
关键在最后一行:s-maxage 存在时,边缘优先用它,浏览器仍然用 max-age。两侧因此可以分开调。
# 边缘存 30 天,浏览器只存 1 小时
cache-control: public, s-maxage=2592000, max-age=3600这一行的效果是:绝大多数请求由边缘的长副本命中(命中率高、回源少),而任何一次紧急修复最多 1 小时就能全量覆盖。
什么时候该用 immutable
如果文件名里带内容哈希(如 app.4f2a1c.js),文件内容永不改变——改的是文件名。这时上面的顾虑不存在,可以放心用最长 TTL:
cache-control: public, max-age=31536000, immutable- immutable 额外告诉浏览器:连「刷新页面时顺便验证一下」都不必做;
- 没有它,用户按刷新键仍会为每个文件发一次条件请求(304),白付一次往返延迟;
- 但这一切的前提是文件名真的带哈希——对 index.html 用 immutable 是灾难。
在你的网站验证
边缘核验解析你的 cache-control,并指出 s-maxage 是否缺失