HTML 不应强缓存,应作为索引页仅缓存带内容哈希的静态资源;含用户态页面用 no-cache,敏感页用 no-store;Nginx 需按类型分离配置,CDN 需显式设置;Service Worker 是唯一可靠离线方案。

HTML 文件本身不值得缓存——缓存它不仅提速有限,还极易导致用户看到旧文案、错乱按钮、甚至加载失败的 JS 路径。真正起效的是把 HTML 当作“索引页”,让浏览器只缓存它引用的 main.a1b2c3.js、style.4d5e6f.css 这类带内容哈希的静态资源。
为什么给 index.html 加 Cache-Control: public, max-age=3600 是危险操作
强缓存会跳过服务器验证,而绝大多数 HTML 不带 ETag 或 Last-Modified,浏览器无法判断内容是否更新。结果就是:你上线了新版本 JS,但用户打开的仍是旧 index.html,里面还引用着已删除的 old-button.js,控制台报 404,页面白屏。
- 纯静态文档页(如 GitHub Pages 的 README 渲染页)可设
Cache-Control: public, max-age=300(5 分钟),平衡 CDN 回源压力与更新及时性 - 含用户态的页面(如仪表盘、订单列表)必须用
Cache-Control: no-cache,强制每次发请求,靠服务端返回304 Not Modified减少传输 - 登录页、支付确认页等敏感页,只能用
Cache-Control: no-store,彻底禁用任何中间环节缓存 -
meta http-equiv="Cache-Control"在 Chrome/Firefox/Edge 中完全无效,仅旧版 Safari 可能降级识别,别写
Nginx 配置中 HTML 和静态资源必须分离策略
把 HTML 和 JS/CSS 混在同一个缓存规则里,等于把“易变索引”和“稳定资产”锁死在一起。Nginx 的 location 块必须按文件类型拆开配:
location = /index.html {
add_header Cache-Control "no-cache";
}
location ~* \.(css|js|woff2|png|jpg|gif)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
-
immutable关键字能让浏览器跳过后续的If-None-Match请求,省一次往返 - JS/CSS 必须由构建工具输出带 content hash 的文件名(Webpack 的
[contenthash],Vite 默认行为),否则expires 1y会锁死旧逻辑 - CDN 缓存规则不能依赖源站 header,必须在 CDN 控制台显式配置,否则容易被覆盖
Service Worker 是唯一能真正实现 HTML 级离线加载的方案
HTTP 缓存不是为离线设计的。断网时,浏览器连 index.html 的请求都发不出去,更别说验证是否过期。只有 Service Worker 能在请求发出前拦截并返回预存的 HTML 副本。
- 它必须通过 HTTPS(或
localhost)注册,HTTP 环境下直接静默失败 - 缓存 HTML 时不能只存一份,要同时缓存它依赖的所有资源(
index.html+main.a1b2c3.js+style.4d5e6f.css),否则离线后 HTML 虽能加载,但 JS 报 404 - 更新 SW 脚本后,旧缓存不会自动清理,需手动在
install或activate阶段调用cache.delete() - 首次访问不会触发 SW 缓存,因为脚本还没注册;第二次访问才生效——这个延迟常被忽略
最复杂的点不在怎么配 header,而在于 HTML 和它引用资源的缓存生命周期是否对齐。一个没 hash 的 main.js,配上 immutable,比不缓存还糟;一个带 hash 的 JS,却配了 no-cache 的 HTML,等于白做。缓存不是开关,是链路协同。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











