PWA中fetch拦截不生效是怎么回事?
我在Service Worker里写了fetch事件监听,想缓存网络请求,但好像根本没触发,页面请求还是直接走网络。是不是注册顺序有问题?
我试过把register写在DOMContentLoaded之后,也确认了SW状态是activated,但fetch事件就是不进handler。代码大概是这样:
self.addEventListener('fetch', (event) => {
console.log('拦截到请求:', event.request.url);
event.respondWith(
caches.match(event.request).then(cached => {
return cached || fetch(event.request);
})
);
});
对,就是这么坑爹。你代码写得没问题,SW状态也activated了,但页面还是老样子,因为浏览器不会自动切换已打开页面的控制权。
具体说,页面只有在两种情况下会被SW接管:
1. 首次加载时SW就注册成功并激活
2. 注册成功后刷新页面
你现在的情况大概率是页面在SW激活前就加载完成了,所以根本没被接管。
解决思路:
第一步,确认页面是否被SW控制。在控制台执行:
如果返回null,说明页面没被控制。返回对象说明被控制了。
第二步,如果确认没被控制,最简单的办法:刷新页面。刷新后fetch事件就应该能正常拦截了。
第三步,如果刷新了还是不行,检查作用域。假设你的HTML在根目录,SW文件放在js/sw.js,默认作用域是基于SW文件位置的,所以js目录下的请求可能被拦截,根目录的请求不一定行。注册时需要指定scope:
第四步,打开浏览器开发者工具的Application面板,确认Service Worker状态是Activated且Running,同时检查Is run checkbox是否勾选(有些浏览器可以手动禁用SW)。
最后提醒一点,console.log在SW里是输出到开发者工具的Console面板,不是页面的Console,这个也容易让人误解事件没触发。
还有个常见坑:如果你在localhost开发,某些浏览器对localhost有特殊处理,最好用127.0.0.1或者配置https。
你现在先试试刷新页面,大概率就解决了。