Service Worker 需手动注册、监听fetch并管理缓存策略,强制HTTPS(本地除外),常见错误包括MIME类型错误、scope缺失、未预缓存HTML等;离线能力取决于具体缓存逻辑实现。

Service Worker 是浏览器后台运行的脚本,能拦截网络请求、缓存资源、实现离线访问——但它不是“开箱即用”的离线开关,必须手动注册、监听 fetch 事件、并主动管理缓存策略。
Service Worker 必须通过 HTTPS 注册(本地开发除外)
浏览器强制要求:线上环境必须在 HTTPS 下注册 serviceWorker,否则 navigator.serviceWorker.register() 会直接失败并抛出 TypeError。localhost 和 127.0.0.1 被豁免,可本地调试。
常见错误现象:
-
Uncaught DOMException: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/html')—— 检查服务器是否返回了正确的Content-Type: text/javascript -
Uncaught (in promise) DOMException: Registration failed – no scope provided——register()的第二个参数{scope: '...'}缺失或路径不合法(scope 不能高于 service worker 文件所在目录)
注册后需手动监听 fetch 并决定缓存逻辑
注册成功 ≠ 自动离线。Service Worker 默认不缓存任何请求,你必须在 SW 脚本中监听 fetch 事件,并显式调用 caches.match() 或 fetch()。
典型缓存策略示例(优先读缓存,缓存未命中再发网络请求):
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
if (response) return response;
return fetch(event.request);
})
);
});
注意点:
-
caches.open('v1')必须先调用,否则caches.match()返回undefined - 静态资源(HTML/CSS/JS)建议在
install事件中预缓存,避免首次 fetch 时缓存为空 -
fetch()请求默认不带 cookies,如需认证,得加{credentials: 'include'}
缓存更新机制容易被忽略:install → activate → cleanup 需手动触发
新版本 SW 文件部署后,旧版仍会持续控制页面,直到所有打开的页面关闭、或调用 skipWaiting() + clients.claim() 强制接管。
常见陷阱:
- 修改了 SW 文件但页面没刷新,
fetch仍走旧逻辑 —— 检查 DevTools > Application > Service Workers 是否显示 “Waiting” 状态 - 缓存名没升级(比如还用
'v1'),导致新 SW 读的是旧缓存 —— 每次变更缓存策略必须改 cacheName - 旧缓存没清理,磁盘越积越多 —— 在
activate事件中遍历caches.keys()删除非当前版本缓存
离线功能依赖资源是否真正进缓存,而非“有 SW”
很多开发者以为注册了 SW 就能离线,结果发现 HTML 页面打不开——因为根路径 / 的 HTML 没被预缓存,而 SW 的 fetch 事件里又没对 HTML 做 fallback 处理。
实操建议:
- 在
install阶段用caches.addAll(['/', '/index.html', '/app.js'])预加载关键资源 - 对 HTML 请求单独 fallback 到
/offline.html(用Response.redirect()或构造new Response(htmlString, {headers})) - 动态资源(如 API)不适合全量缓存,应结合
stale-while-revalidate策略,在fetch中判断event.request.destination === 'json'分流处理
离线能力不是靠 Service Worker 自身,而是靠你写的每一条 caches.put()、每一次 event.respondWith() 决定的。最容易被跳过的环节是缓存命名更新和 activate 清理,这两步漏掉,离线行为就会不可预测。










