Service Worker 需手动注册、配置缓存策略并劫持请求才能实现离线功能,必须通过 HTTPS(或 localhost)注册,install 预缓存静态资源,fetch 中主动匹配缓存,配合 skipWaiting() 和 clients.claim() 确保新版本立即生效。

Service Worker 是浏览器中运行在独立线程里的脚本,它不绑定具体页面,能拦截、修改、响应网络请求,并支持后台消息、推送和离线缓存——但它不是“自动让网站离线”的开关,必须手动注册 + 缓存策略 + 请求劫持三者配合才能生效。
Service Worker 必须用 HTTPS(或 localhost)才能注册
这是硬性安全限制,生产环境 HTTP 域名下 navigator.serviceWorker.register() 会直接失败,控制台报错 Failed to register a ServiceWorker: Scheme 'http' is not supported。开发时可用 localhost 绕过,但 127.0.0.1 或自定义 hosts 域名(如 dev.local)不行,除非配了 HTTPS。
- 本地开发建议用 Vite、Webpack Dev Server 或
npx http-server -S启用 HTTPS - CI/CD 部署前确认 Nginx/Apache 返回的
Strict-Transport-Security头没误配导致 HSTS 强制跳转失败 - 注册代码必须放在页面加载后执行,且不能包裹在
document.addEventListener('DOMContentLoaded', ...)里——因为 SW 注册是同步发起的,等 DOM 就晚了
缓存策略靠 install 和 fetch 事件协同完成
只在 install 里调用 caches.open().then(cache => cache.addAll([...])) 只是预加载静态资源;真正让页面离线可用,得在 fetch 事件里主动从缓存读取,否则浏览器仍会发网络请求并失败。
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
// 缓存命中:返回缓存
if (response) return response;
// 缓存未命中:发网络请求,并顺手存入缓存(可选)
return fetch(event.request).then(networkResponse => {
if (networkResponse && networkResponse.status === 200) {
const copy = networkResponse.clone();
caches.open('v1').then(cache => cache.put(event.request, copy));
}
return networkResponse;
});
})
);
});
-
caches.match()匹配的是完整 URL(含 query 参数),/index.html?v=2和/index.html是两个不同缓存项 - 动态接口(如
/api/user)默认不被cache.addAll()包含,需在fetch中按需缓存,注意设置合理Cache-Control或手动加 TTL 判断 - 不要在
fetch里无条件return fetch(...),那等于没走缓存
skipWaiting() 和 clients.claim() 决定新 SW 何时生效
默认情况下,已打开的页面仍使用旧版 SW,即使新版本已安装完成。用户必须刷新两次才能用上新版逻辑——第一次触发 install,第二次才让新 SW 控制页面。
立即学习“Java免费学习笔记(深入)”;
- 在新 SW 的
install事件末尾加self.skipWaiting(),跳过 waiting 状态 - 在
activate事件里调用self.clients.claim(),让新 SW 立即接管所有当前客户端(包括已打开的 tab) - 这两步不加,离线缓存更新后页面可能仍走旧逻辑,表现为“明明改了缓存名单,但离线时还是加载老资源”
最易被忽略的一点:Service Worker 的生命周期由浏览器严格管理,它可能随时被终止(比如内存紧张时),所以不能依赖全局变量存状态,所有关键数据必须写入 IndexedDB 或 caches;另外,console.log 在 SW 里默认不输出到页面控制台,得打开 Chrome 的 Application → Service Workers 面板勾选 “Update on reload” 并看专用日志。











