service worker注册失败主因是https或路径问题,离线打不开html多因request.destination判断错误或缓存不全;注册须在window.load中执行并加特性检测;cache.addall()需根路径且无查询参数;sw.js响应头必须允许缓存。

Service Worker 注册失败,八成是 HTTPS 或路径问题;离线打不开 HTML,几乎一定是 request.destination 没判对或缓存资源不全。
注册代码必须放在 window.addEventListener('load', ...) 里
放在 DOMContentLoaded 或异步模块中会静默失败——SW 需要完整 DOM 和全局上下文才能建立作用域。浏览器在页面未完全加载时可能拒绝注册,且不会抛错。
- 错误写法:
document.addEventListener('DOMContentLoaded', () => navigator.serviceWorker.register('/sw.js')) - 正确写法:
window.addEventListener('load', () => navigator.serviceWorker.register('/sw.js')) - 务必加
if ('serviceWorker' in navigator)安全判断,避免不支持环境报错 - 注册后记得检查 DevTools → Application → Service Workers 面板,Status 是
Waiting表示新版本已安装但未激活(需手动点Skip waiting或刷新两次)
cache.addAll() 的路径必须以 / 开头,且不能含查询参数
cache.addAll() 是预缓存静态资源最常用方式,但它只接受同源、根相对路径(即相对于 origin),且对任意一个资源返回非 2xx 状态(如 404 图片、CORS 字体)就会整批失败,一个都不缓存。
- 错误写法:
['index.html', './style.css']→ 会尝试请求https://yoursite.com/current-path/index.html,大概率 404 - 正确写法:
['/', '/index.html', '/styles/main.css', '/images/logo.png'] - 禁止写
'/data.json?v=1.2':不同参数被视为不同 URL,浪费缓存空间,且无法命中 - HTML 文件建议单独处理:
cache.put(new Request('/'), new Response(...)),避免依赖服务端重定向或 fallback 行为
fetch 事件里必须用 request.destination === 'document' 判断导航请求
浏览器对页面导航(比如地址栏输入、刷新、点击链接)和资源请求(fetch()、<img>、<script></script>)的 request.destination 值不同。不区分就直接 caches.match(event.request),会导致 API 请求被缓存响应覆盖、POST 表单静默失败、字体/CSS 加载中断等严重问题。
- 导航请求(HTML 页面):
event.request.destination === 'document' - 脚本请求:
event.request.destination === 'script' - 图片请求:
event.request.destination === 'image' - API 请求(如
fetch('/api/user')):event.request.destination === 'empty'(注意不是'json') - 推荐逻辑:对
document类型先查缓存,无则返回预置offline.html;对script/style用缓存优先;对empty类型用网络优先 + 备用响应
离线 HTML 打不开?先看 sw.js 是否被禁止缓存
sw.js 文件本身若被服务器加上 Cache-Control: no-store 或 max-age=0,浏览器会拒绝注册,控制台只显示 Failed to register a ServiceWorker,没有任何线索。
- 检查方式:直接访问
https://yoursite.com/sw.js,看响应头中Cache-Control是否允许缓存(至少public, max-age=3600) - 常见踩坑:Webpack/Vite 开发服务器默认禁用 SW 缓存,需显式配置
headers: { 'Cache-Control': 'public, max-age=3600' } - 生产环境 Nginx 示例配置:
location = /sw.js { add_header Cache-Control "public, max-age=3600"; } - 另外确认
sw.js内容每次更新都有变化(哪怕加个空格),否则浏览器认为“没更新”,跳过安装流程
真正卡住人的地方往往不是代码怎么写,而是 sw.js 路径对不对、request.destination 判没判准、以及那个藏在响应头里的 Cache-Control ——它们不出错时不显眼,一出错就整个离线链路瘫痪,且毫无提示。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











