PWA离线缓存怎么不生效?明明注册了service worker啊

东方玉鑫 阅读 87

我按照教程写了 service worker,也成功注册了,在 DevTools 的 Application 面板里能看到它处于 active 状态。但一断网页面就打不开,提示“无法访问此网站”。是不是缓存策略写错了?

我尝试在 install 事件里用 caches.open()addAll() 缓存首页和关键资源,但好像根本没存进去。控制台也没报错,就是离线时完全不能用。

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('v1').then((cache) => {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles/main.css',
        '/scripts/app.js'
      ]);
    })
  );
});
我来解答 赞 11 收藏
二维码
手机扫码查看
2 条解答
打工人书妍
看起来你已经完成了基本的 service worker 注册和安装步骤,但离线功能还是没生效。我来帮你一步步排查和改进这个问题。

首先你要确认你的 fetch 事件处理程序有没有正确实现。光是 install 阶段缓存了文件还不够,你需要在 fetch 事件中拦截请求并从缓存返回内容。这里有个完整的示例:

self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
// 在安装阶段预缓存关键资源
return cache.addAll([
'/',
'/index.html',
'/styles/main.css',
'/scripts/app.js'
]).catch(error => {
console.error('缓存失败: ', error); // 这里加个错误日志,方便调试
});
})
);
});

// 加上这个 fetch 事件监听器
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
// 如果缓存中有匹配的内容,直接返回
if (response) {
return response;
}
// 否则继续请求网络资源
return fetch(event.request);
}).catch(() => {
// 网络请求失败时,尝试加载一个备用页面
if (event.request.mode === 'navigate') {
return caches.match('/offline.html');
}
})
);
});


注意几个要点:
- 我们在 fetch 事件中使用 caches.match() 查找缓存中的响应
- 如果没有缓存命中,我们继续发出网络请求
- 对于导航请求(用户访问网页),如果所有方法都失败,我们可以提供一个离线页面

关于为什么之前不生效,很可能是因为你缺少 fetch 事件处理逻辑。默认情况下,浏览器会跳过缓存直接访问网络,除非你明确指定要使用缓存。

另外一个小建议:你可以在 Chrome DevTools 的 Application 面板里手动触发 service worker 更新,或者在 sw 文件中加入 self.skipWaiting() 来加快更新速度。

最后别忘了测试的时候清除一下浏览器缓存,有时候旧的缓存会影响调试结果。开发者工具里有"Disable Cache"选项,打开它能避免一些奇怪的问题。
点赞
2026-03-29 21:20
可欣
可欣 Lv1
这个问题很典型,十有八九是你少写了一个关键的东西:fetch 事件监听器。

你只写了 install 事件来缓存资源,但这只是把东西存到缓存区里。Service Worker 还需要拦截页面发出的网络请求,从缓存里把东西返回给页面。这两个是缺一不可的。

来,加上 fetch 事件的处理:

// 拦截网络请求
self.addEventListener('fetch', (event) => {
event.respondWith(
// 先去缓存里找
caches.match(event.request).then((response) => {
// 如果缓存里有,直接返回
if (response) {
return response;
}
// 缓存里没有,去网络请求
return fetch(event.request);
})
);
});


把这段代码加到你的 service worker 文件里,然后重新注册一下。更新 service worker 有个小技巧,建议在注册时加上这样一段:

if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then((registration) => {
console.log('SW 注册成功:', registration);
}).catch((error) => {
console.log('SW 注册失败:', error);
});
}


注册成功后,去 Application 面板里刷新一下,然后勾选 Offline 选项,再刷新页面试试能不能打开。

另外还有几个可能踩坑的地方:

缓存的路径要对得上。如果你的页面是通过 / 访问的,那就缓存 /,如果是通过 /index.html 访问的,那就两个都缓存上,别漏了。

更新缓存要换名字。你现在的缓存名叫 v1,下次想更新缓存内容的时候,得改成 v2 或者别的名字,不然浏览器会一直用旧缓存。懒人才不想改名字的话,可以写个自动清理旧缓存的逻辑。

调试的时候用 DevTools。Application 面板里能看到 Cache Storage,看看里面有没有你缓存的文件。如果缓存是空的,说明 addAll 可能失败了,可能是路径写错了或者服务器没返回正确的响应。

你先加上 fetch 事件监听器试试,大概率就能工作了。
点赞
2026-03-14 15:03