这个坑最近特别多人踩——91大事件:关于缓存设置的说法:最要命的是这一句提示!我先把要点列出来

前言 最近在帮朋友排查网站更新不生效、用户看到旧资源、CDN 无法及时同步这些问题时,发现大多数错误并不是出在复杂的逻辑上,而是出在对缓存概念和一个常见提示的误读上。先给出要点清单,再逐项展开,方便你边看边对照排查。
要点清单(先过个总览)
- 最致命的误读:把“Cache-Control: no-cache”当成“完全不缓存”。
- 常见误区还包括:把 HTML 页面也设置超长缓存、误用 immutable、Service Worker 未正确更新、CDN 未及时清理或配置 TTL 不当。
- 判断问题的第一步:用浏览器 DevTools 看请求头和响应头(关注 Cache-Control、Expires、ETag、Last-Modified、Vary、Age、x-cache)。
- 推荐策略:静态资源长期缓存 + 文件名带 hash(缓存穿透法);HTML 页面短缓存或不缓存 + 合理的 revalidation。
- 快速解决清单:检查响应头 → 检查 CDN 配置 → 检查 Service Worker → 强制刷新/清空 CDN 缓存 → 使用 hash 发布静态资源。
最要命的一句提示 很多人看到服务器或浏览器里的这一行:Cache-Control: no-cache,就以为“资源不会被缓存”“浏览器每次都会去服务器取最新版本”。这种理解会导致把静态资源设置得很宽松或错误配置,结果要么频繁回源影响性能,要么误设为“长时间缓存”以求保守,反而让更新推不出去。
澄清一下“no-cache”的真实含义
- Cache-Control: no-cache 表示缓存可以存储资源,但在使用前必须向服务器重新验证(revalidate)。并不是“禁止缓存”。
- Cache-Control: no-store 才是“不要存储任何缓存副本”的意思(更绝对)。
- Cache-Control: max-age=31536000, immutable 则告诉浏览器这资源一年内不需要重新验证(适合带 hash 的静态文件)。
把这些词混着用或误读,会造成问题。
常见坑与场景举例(和解决思路) 1) 页面更新了,但用户浏览器仍显示旧页面
- 原因常见:HTML 页面被设置了长时间缓存,或者 Service Worker 缓存策略错误,或者 CDN 仍在使用旧边缘缓存。
- 排查:DevTools Network 看 HTML 请求是否从 cache 或 CDN 返回(关注 status、Age、x-cache 等)。检查响应头是否包含长 max-age 或 immutable。检查是否有 Service Worker 拦截并返回旧缓存。
- 解决:把 HTML 设置为短缓存或 no-store,或使用短 TTL + 强制 revalidate;如果采用 Service Worker,设计好更新流程(skipWaiting + clients.claim + 清理旧缓存);对 CDN 做缓存清理或版本发布策略。
2) 静态资源(JS/CSS/图片)一直请求到服务器,没利用缓存
- 原因:没有使用文件名 hash,或设置了 no-store/no-cache 不当,或响应头缺少 Cache-Control/Expires。
- 解决:在构建阶段对静态资源加上内容 hash(例如 app.abc123.js),设置 Cache-Control: public, max-age=31536000, immutable。服务器和 CDN 同步设置。
3) 304 Not Modified 看起来“正常”,但用户仍看到旧内容
- 说明:304 是浏览器向服务器验证后得到的结果,服务器认为资源没变,所以返回 304,浏览器使用本地缓存副本。如果本地缓存其实已经损坏或服务端逻辑错误导致没更新,问题会出现。
- 排查:检查 ETag/Last-Modified 是否正确,是否构建流程没有改变资源 hash,但内容变了(构建问题)。建议对静态资源用文件名 hash 而不是单靠 ETag。
4) CDN 侧未能即时更新或边缘缓存混乱
- 原因:CDN TTL 设置过长、没有自动刷新、或者使用了错误的缓存键(比如忽略 query string)。
- 解决:使用版本化资源(hash),在发布时触发 CDN 清理或通过版本变更来强制落地。检查 CDN 是否按预期传递源站的 Cache-Control。
常用 header 及推荐配置(按资源类型)
-
HTML 页面(动态、频繁变动)
-
推荐:Cache-Control: no-store 或 Cache-Control: private, no-cache, must-revalidate
-
解释:确保用户每次或至少每次打开页面时能得到最新 HTML(但静态资源仍可缓存)。
-
静态资源(带 hash 的 JS/CSS/图片)
-
推荐:Cache-Control: public, max-age=31536000, immutable
-
解释:文件名已包含 hash,文件内容变更会改变文件名,故可长期缓存并提升性能。
-
API 响应
-
推荐:视业务而定,一般 JSON 数据用短 TTL(max-age=0, must-revalidate)或 no-cache,缓存控制混合使用 ETag 来做条件请求。
Nginx 示例(设置静态资源长缓存,HTML 短缓存)
- 静态资源(例如 /static/ 带 hash 的目录): add_header Cache-Control "public, max-age=31536000, immutable";
- HTML(根路径) add_header Cache-Control "private, no-cache, must-revalidate";
Apache 示例
- 静态资源:
Header set Cache-Control "public, max-age=31536000, immutable" - HTML:
Header set Cache-Control "private, no-cache, must-revalidate"
Service Worker 常见问题与建议
- 问题:Service Worker 缓存策略写得太“聪明”,未处理更新逻辑,导致用户一直被旧缓存覆盖。
- 建议:实现清晰的缓存版本号;当页面 detect 到新版本时,调用 skipWaiting 并在激活阶段清理旧缓存;在客户端向用户提示“有新版本,刷新以更新”作为兜底。
调试步骤清单(按顺序)
- 用无痕/清除缓存的浏览器访问,看是否仍旧出现问题。
- DevTools -> Network,勾选 Disable cache(在 DevTools open 时),刷新,观察请求响应头(Cache-Control、ETag、Age、x-cache)。
- 检查服务器端响应头配置(用 curl -I URL 查看)。
- curl -I https://example.com/path
- 检查 CDN 控制台的边缘缓存策略和缓存键设置,确认是否需要清理或调整 TTL。
- 如果用 Service Worker,打开 Application -> Service Workers,检查是否启用并查看缓存存储(Cache Storage)。
- 验证构建工具是否在静态资源上做了 hash,检查发布流程是否正确替换页面引用。
快速实操命令示例
- 查看响应头(终端): curl -I https://yourdomain.com/index.html
- 强制刷新 CDN(示例,按你的 CDN 控制台操作)
- 清除 Service Worker(浏览器 DevTools -> Application -> Unregister Service Worker)
发布与版本策略建议(降低踩坑概率)
- 静态资源务必用内容哈希(content hash)并作为文件名的一部分。
- HTML 主文档使用短缓存或禁止缓存,静态资源长期缓存。
- 在 CI/CD 中加入自动化 CDN 清理或采用版本化 URL。
- 为 Service Worker 设计明确的升级策略与用户提示机制。
常见术语快速对照(避免混淆)
- no-cache ≠ 不缓存(需要 revalidate)
- no-store = 不存储任何缓存副本
- max-age = 以秒为单位的缓存时间(0 表示立即过期,但行为要看其他指令)
- immutable = 表示资源内容不会改变(通常用于带 hash 的静态资源)
- ETag/Last-Modified = 用于条件请求和 revalidation(可结合使用)
结语 很多“缓存问题”其实不是神秘的 bug,而是对某一句提示或某个 header 的误读导致配置选择错路。把握两个核心策略就够实用:静态资源用 hash 并长期缓存,动态页面短缓存或及时 revalidate;Service Worker 与 CDN 要么按规则严格管理,要么在发布流程里设计好版本失效机制。遇到问题,按调试步骤一步步拆解,基本可以很快定位并修复。
需要我帮你检查具体的响应头或给出你服务器和 CDN 的具体配置建议吗?把 curl -I 的输出或 DevTools 的响应头贴上来,我可以逐项帮你分析。

最新留言