Service Worker 可拦截 fetch 请求实现缓存与离线访问,需 HTTPS 环境注册;通过 install 预缓存、fetch 事件按策略响应(HTML 缓存优先+网络回退,静态资源缓存优先+后台更新),并处理离线 fallback 与缓存版本更新。

Service Worker 可以在浏览器后台拦截页面发出的 fetch 请求,从而实现资源缓存与离线访问。关键在于注册 Service Worker、监听 fetch 事件,并在其中自定义响应逻辑——不是所有请求都适合缓存,需按策略区分处理。
注册并激活 Service Worker
必须在 HTTPS 环境(或 localhost)下运行。在主页面 JS 中注册:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW registered:', reg))
.catch(err => console.error('SW registration failed:', err));
});
}
注册后,浏览器会下载并安装 sw.js。首次安装时触发 install 事件,可在此预缓存核心静态资源(如 HTML、CSS、JS):
self.addEventListener('install', event => {
event.waitUntil(
caches.open('static-v1').then(cache =>
cache.addAll([
'/',
'/index.html',
'/app.css',
'/app.js'
])
)
);
});
拦截 fetch 请求并返回缓存响应
在 fetch 事件中判断请求是否命中缓存,优先返回缓存内容,缓存未命中再发起网络请求,并可选择性更新缓存:
self.addEventListener('fetch', event => {
const { request } = event;
// 仅对 GET 请求做缓存处理(POST/PUT 等通常不缓存)
if (request.method !== 'GET') return;
// 对 HTML 页面使用「缓存优先 + 网络回退」策略
if (request.destination === 'document') {
event.respondWith(
caches.match(request).then(cached => cached || fetch(request))
);
return;
}
// 对静态资源(JS/CSS/IMG)采用「缓存优先 + 后台更新」策略
if (request.destination === 'script' ||
request.destination === 'style' ||
request.destination === 'image') {
event.respondWith(
caches.match(request).then(cached => {
// 缓存存在,直接返回
if (cached) return cached;
// 缓存不存在,取网络响应并写入缓存(不阻塞返回)
return fetch(request).then(response => {
const copy = response.clone();
caches.open('static-v1').then(cache => cache.put(request, copy));
return response;
});
})
);
return;
}
});
处理离线状态与用户提示
当网络不可用时,fetch(request) 会抛出异常。可在 fetch 事件中捕获并返回兜底响应:
- 为 HTML 页面提供离线 fallback 页面(如
/offline.html),提前缓存好 - 在
fetch事件中对 document 请求增加错误处理:
event.respondWith(
caches.match(request)
.then(cached => cached || fetch(request))
.catch(() => caches.match('/offline.html'))
);
也可在页面 JS 中监听 navigator.onLine 或监听 Service Worker 的 controllerchange 事件,提示用户当前处于离线模式。
更新缓存与版本控制
Service Worker 更新靠文件内容变化触发。每次修改缓存策略或资源列表,需更新缓存名称(如 'static-v2'),并在 activate 事件中清理旧缓存:
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(
keys
.filter(key => key.startsWith('static-') && key !== 'static-v2')
.map(key => caches.delete(key))
)
)
);
});
注意:新 Service Worker 激活后,旧页面仍由旧 SW 控制,需刷新或跳转才能启用新版逻辑。










