PWA中拦截fetch请求时如何正确返回缓存数据?

Code°园园 阅读 18

在开发PWA时,我尝试用Service Worker拦截fetch请求,想在网络错误时返回缓存数据。但发现当网络断开时,某些请求返回了504而不是缓存内容,这是为什么?

我的service worker代码类似这样:


self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then(cacheRes => {
      return cacheRes || fetch(event.request);
    })
  );
});

测试时发现,当第二次请求且断开网络,明明缓存存在却还是报错。难道是fetch顺序有问题?或者需要手动处理网络状态?

我来解答 赞 4 收藏
二维码
手机扫码查看
2 条解答
百里巧梅
你的问题是网络断开时没正确降级到缓存,这是因为 fetch 抛出异常后没有捕获。我之前也踩过这坑,改一下代码逻辑就行。

self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(cacheRes => {
return cacheRes || fetch(event.request).catch(() => caches.match(event.request));
})
);
});


简单说就是加个 .catch,网络挂了就强制走缓存。别忘了测试各种断网场景,不然还是会出幺蛾子。
点赞
2026-02-17 17:06
 ___广运
这个问题我也踩过坑,说白了就是你的缓存逻辑漏了一步网络异常的处理。你现在的代码是先查缓存,如果缓存没有就直接去发起网络请求。但问题来了,当网络断开时,fetch会抛出异常,而不是返回一个可用的响应,所以你的代码在这种情况下就挂了。

我的血泪教训是,在 PWA 的 Service Worker 里,处理 fetch 请求一定要有兜底逻辑。具体来说,你需要捕获 fetch 的异常,并在捕获到异常时再次尝试从缓存中获取数据。下面是改好的代码:

self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(cacheRes => {
// 如果缓存命中,直接返回缓存
if (cacheRes) return cacheRes;
// 否则尝试发起网络请求
return fetch(event.request).catch(() => {
// 网络请求失败时再次尝试返回缓存
return caches.match(event.request);
});
})
);
});


这里的关键点有两个:第一,你要用 catch 捕获 fetch 抛出的异常;第二,catch 里面再次调用 caches.match,这样即使网络断开了,也有机会从缓存里拿数据。

另外提醒一下,caches.match 是按请求 URL 和方法匹配的,所以如果你的缓存策略有问题,比如只缓存了 GET 请求而你的应用发的是 POST 请求,那还是拿不到缓存数据。我之前就因为这个原因折腾了半天,最后发现是因为没缓存对应的请求类型。

总结一下,核心思路就是:优先查缓存,然后发网络请求,再用 catch 兜底处理网络异常。这样无论网络状态如何,你的应用都能尽量优雅地降级到缓存数据。
点赞 2
2026-02-17 10:03