PWA中fetch拦截不生效是怎么回事?

A. 树鹤 阅读 4

我在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);
    })
  );
});
我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
Des.怡玥
这个问题的根本原因是:Service Worker注册成功后,需要刷新页面才能让SW真正控制页面。

对,就是这么坑爹。你代码写得没问题,SW状态也activated了,但页面还是老样子,因为浏览器不会自动切换已打开页面的控制权。

具体说,页面只有在两种情况下会被SW接管:
1. 首次加载时SW就注册成功并激活
2. 注册成功后刷新页面

你现在的情况大概率是页面在SW激活前就加载完成了,所以根本没被接管。

解决思路:

第一步,确认页面是否被SW控制。在控制台执行:

navigator.serviceWorker.controller


如果返回null,说明页面没被控制。返回对象说明被控制了。

第二步,如果确认没被控制,最简单的办法:刷新页面。刷新后fetch事件就应该能正常拦截了。

第三步,如果刷新了还是不行,检查作用域。假设你的HTML在根目录,SW文件放在js/sw.js,默认作用域是基于SW文件位置的,所以js目录下的请求可能被拦截,根目录的请求不一定行。注册时需要指定scope:

navigator.serviceWorker.register('/sw.js', {
scope: '/' // 明确指定作用域为根目录
}).then(reg => {
console.log('SW注册成功');
});


第四步,打开浏览器开发者工具的Application面板,确认Service Worker状态是Activated且Running,同时检查Is run checkbox是否勾选(有些浏览器可以手动禁用SW)。

最后提醒一点,console.log在SW里是输出到开发者工具的Console面板,不是页面的Console,这个也容易让人误解事件没触发。

还有个常见坑:如果你在localhost开发,某些浏览器对localhost有特殊处理,最好用127.0.0.1或者配置https。

你现在先试试刷新页面,大概率就解决了。
点赞
2026-03-12 18:00