html文件必须显式缓存,否则离线时白屏;因cache.addall()是原子操作,路径须为绝对根路径,且html应走network-first策略避免版本滞留。

HTML 文件必须显式进入缓存,否则离线就是白屏
离线时打不开页面?不是 Service Worker 没注册成功,而是 index.html 根本没进缓存。很多开发者只缓存了 app.js 和 style.css,却忘了把 HTML 本身加进 cache.addAll() 列表里——结果断网后浏览器连文档结构都拿不出来,直接 net::ERR_FAILED 或空白页。
关键点:
-
cache.addAll()是原子操作:列表里任意一项失败(比如/index.html返回 404 或带Cache-Control: no-store),整个缓存就中止,一个文件都不会存 - 路径必须是绝对根路径:
'/index.html'✅,'index.html'❌(相对路径在 SW 中解析为当前脚本所在目录) - 服务端对
/的响应不能是 SSR 动态页且含禁止缓存头;建议设为Cache-Control: public, max-age=0,让 SW 全权控制
HTML 不该被长期缓存,否则版本滞留无法回滚
把 index.html 像 JS/CSS 那样放进 CacheStorage 并长期 serve,等于把动态入口钉死在旧版本上。用户刷新看到的永远是部署前的 DOM 结构,哪怕你已上线修复 bug 的新 HTML ——因为 SW 直接返回了缓存副本,根本没走网络。
更危险的是回滚场景:线上 HTML 出现严重渲染错误,你发版修复,但用户本地 SW 仍在 serve 带 bug 的 HTML,除非手动清缓存或关掉所有标签页。
正确做法:
- HTML 走
network-first或stale-while-revalidate策略,保证每次加载都是最新版本 - 其他资源(
app.js、logo.png等)才用cache-first - 若需校验 HTML 完整性,可在
<meta name="sw-version">中注入构建哈希,在 SW 的fetch事件里解析并比对,不匹配则拒绝缓存
HTML 内联脚本和动态注入内容不会被缓存
你在 index.html 里写 <script>document.write('<div id="app">')</script>,或者服务端注入 <meta name="version" content="2.1">,这些内容在离线时会失效或固定不变。
原因很直接:
-
document.write()是运行时执行的,Service Worker 缓存的是 HTML 响应体原始字节,不包含 JS 执行后的 DOM - 服务端模板变量(如 PHP/Node 渲染的
content)在缓存那一刻就固化了,后续部署不会更新它 - 离线状态下,任何依赖网络的动态行为(如 fetch 接口、CDN 字体)都会中断,导致结构缺失或样式错乱
HTTP 协议与部署环境决定离线能力是否启用
Service Worker 只能在 HTTPS 或 localhost 下注册,这是硬性限制。如果你在 http://192.168.1.100 或普通局域网 IP 上调试,navigator.serviceWorker 就是 undefined,注册脚本压根不执行。
常见卡点:
-
sw.js返回 404 或 302 → 检查路径是否匹配,服务器是否配置了静态文件路由 -
sw.js响应头含Cache-Control: no-store→ Nginx/Apache 默认可能加了这类头,需显式覆盖 - 同域名已有激活中的 SW → 新脚本卡在
waiting状态,需在 install 阶段调用self.skipWaiting(),并在页面监听controllerchange后刷新
真正难的不是写几行缓存代码,而是让 HTML 在每次加载时既保持新鲜,又不失可控性——它既是入口,又是状态源,不能简单当成静态文件扔进 cache。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











