Service Worker 是运行在浏览器后台的独立 JavaScript 线程,可拦截作用域内 fetch 请求并定制响应,需 HTTPS(localhost 除外)且通过 navigator.serviceWorker.register() 注册;它支持离线缓存、API Mock、请求重写等,但不可访问 DOM,更新需刷新两次。
JavaScript 本身不能直接拦截页面发起的网络请求(比如 fetch 或 XMLHttpRequest),但可以通过 Service Worker 在浏览器底层实现请求拦截与响应定制。这是现代 Web 应用实现离线缓存、
API Mock、请求重写、鉴权增强等能力的核心机制。
Service Worker 是运行在浏览器后台的独立 JavaScript 线程,它不绑定具体页面,可拦截其作用域(scope)内所有 fetch 请求,并决定是否转发、修改或直接响应。它需要 HTTPS(本地 localhost 除外),且必须通过 navigator.serviceWorker.register() 显式注册。
在主页面的 JS 中调用注册方法,指向一个独立的 SW 脚本文件(如 sw.js):
// main.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW registered:', reg.scope))
.catch(err => console.error('SW registration failed:', err));
});
}
注意:sw.js 必须放在网站根目录或其子目录下,其作用域默认为该路径及其子路径。
通过监听 fetch 事件,你可以捕获所有匹配 scope 的网络请求,并自定义响应逻辑:
// sw.js
self.addEventListener('fetch', event => {
const { request } = event;
// 示例:对 API 请求添加统一 header
if (request.url.includes('/api/')) {
event.respondWith(
fetch(request, {
headers: new Headers({
...Object.fromEntries(request.headers),
'X-From-SW': 'true'
})
})
);
return;
}
// 示例:拦截图片请求,返回占位图
if (request.destination === 'image') {
event.respondWith(
fetch('/placeholder.png')
);
return;
}
// 默认放行
event.respondWith(fetch(request));
});
event.respondWith() 是关键,必须调用,否则请求会失败fetch() 在 SW 中调用时,会绕过 SW 自身,发起真实网络请求request.destination 可区分资源类型(script、image、json、document 等)new Response() 构造模拟响应,实现完全 MockService Worker 常用于:
caches.open() 存储并复用资源注意点:
window、document 等 DOM 对象