渐进式Web应用(PWA)无法加载已缓存静态资源问题求助
问题根因
你当前的Service Worker的fetch事件监听器仅处理了模式为navigate的导航类请求(仅覆盖页面跳转、首次加载页面这类场景),JS脚本、SVG、图标等静态资源的请求不属于navigate模式,没有触发任何缓存匹配逻辑,因此离线时无法返回已缓存的资源内容。
解决方案
修改fetch事件逻辑,增加静态资源的缓存匹配处理,修改后的参考代码如下:
const OFFLINE_VERSION = 1; const CACHE_NAME = "offline"; const OFFLINE_URL = "offline.html"; const BASE = location.protocol + "//" + location.host; const CACHED_FILES = [ "https://cdn.jsdelivr.net/npm/kute.js@2.1.2/dist/kute.min.js", `${BASE}/src/favicon/favicon.ico`, `${BASE}/src/favicon/android-chrome-192x192.png`, `${BASE}/src/favicon/android-chrome-512x512.png`, `${BASE}/src/favicon/apple-touch-icon.png`, `${BASE}/src/favicon/favicon-16x16.png`, `${BASE}/src/favicon/favicon-32x32.png`, `${BASE}/src/svg/layered-waves.svg`, `${BASE}/js/background.js`, `${BASE}/js/animation-blob.js` ]; self.addEventListener('install', (event) => { event.waitUntil((async() => { const cache = await caches.open(CACHE_NAME); await Promise.all( [...CACHED_FILES, OFFLINE_URL].map((path) => { return cache.add(new Request(path, {cache: "reload", mode: 'cors'})); }) ); })()); self.skipWaiting(); }); self.addEventListener('activate', (event) => { event.waitUntil((async () => { // 新增:清理旧版本缓存,避免冗余资源干扰 const cacheKeys = await caches.keys(); await Promise.all( cacheKeys.filter(key => key !== CACHE_NAME).map(key => caches.delete(key)) ); if ("navigationPreload" in self.registration) { await self.registration.navigationPreload.enable(); } })()); self.clients.claim(); }); self.addEventListener('fetch', (event) => { // 处理导航类请求:优先走网络,失败返回离线页 if(event.request.mode === "navigate") { event.respondWith((async() => { try { const preloadResponse = await event.preloadResponse; if(preloadResponse) { return preloadResponse; } return await fetch(event.request); } catch(e) { const cache = await caches.open(CACHE_NAME); return await cache.match(OFFLINE_URL); } })()); return; } // 处理静态资源请求:优先匹配缓存,缓存不存在走网络 event.respondWith((async () => { const cache = await caches.open(CACHE_NAME); // 匹配缓存,ignoreSearch设为true可忽略请求后的查询参数 const cachedRes = await cache.match(event.request, {ignoreSearch: true}); if (cachedRes) { return cachedRes; } // 缓存不存在时尝试发起网络请求 try { const networkRes = await fetch(event.request); // 可选:将新请求到的资源存入缓存,下次离线可直接使用 // cache.put(event.request, networkRes.clone()); return networkRes; } catch (e) { // 可根据资源类型返回对应占位内容,比如图片返回默认占位图 return new Response('', {status: 404}); } })()); });
补充说明
- 代码中新增了
activate阶段的旧缓存清理逻辑,更新Service Worker时会自动删除旧版本的缓存资源,避免冲突 - 给跨域的CDN资源请求增加了
mode: 'cors'配置,可解决部分跨域资源缓存失败的问题 - 如果你的资源请求带有查询参数,
cache.match的ignoreSearch参数会自动忽略参数完成匹配,你可根据实际需求调整
内容的提问来源于stack exchange,提问作者Xeway
相关产品推荐
相关产品推荐

