Service Worker已注册但未缓存资源问题求助
registerRoute未触发 我是Service Worker新手,现在要实现图片和视频的运行时缓存,参考了Workbox的音频视频缓存方案但没生效。Service Worker已经在应用顶级作用域成功注册,但sw.js里的部分代码没执行,核心问题是事件监听器(包括registerRoute)都没被调用,导致缓存根本没创建。
控制台显示sw.js的代码可能在Service Worker注册前就运行了。卡了好久,求帮忙!
相关代码
main.js(Vue 2项目)
if (process.env.NODE_ENV === "production") { window.addEventListener("load", () => { if ("serviceWorker" in navigator) { navigator.serviceWorker .register(`/sw.js`) .then(() => { console.log("Service worker registered!"); navigator.serviceWorker.ready.then((registration) => { registration.update(); console.log('Service Worker: ready'); }); }) .catch((error) => { console.warn("Error registering service worker:"); console.warn(error); }); } }); }
sw.js
import { registerRoute } from "workbox-routing"; import { CacheFirst } from "workbox-strategies"; import { CacheableResponsePlugin } from "workbox-cacheable-response"; import { RangeRequestsPlugin } from "workbox-range-requests"; import { clientsClaim } from "workbox-core"; const CACHE_PREFIX = "background-slideshow-cache"; const CACHE_VERSION = "v1"; const CACHE_RUNTIME = "runtime"; const BACKGROUND_SLIDESHOW_CACHE = `${CACHE_PREFIX}-${CACHE_RUNTIME}-${CACHE_VERSION}`; clientsClaim(); const addToCache = async (url) => { const cache = await caches.open(BACKGROUND_SLIDESHOW_CACHE); if (!(await cache.match(url))) { await cache.add(url); } }; const cacheFirstStrategy = new CacheFirst({ cacheName: BACKGROUND_SLIDESHOW_CACHE, plugins: [ new CacheableResponsePlugin({ statuses: [200], }), new RangeRequestsPlugin(), ], }); self.addEventListener("message", (event) => { if (event.data && event.data.message) { if (event.data.message === "SKIP_WAITING") { self.skipWaiting(); } } }); self.addEventListener("install", (event) => { console.log('Service worker: fetch event', event); }) console.log("Service Worker: in file"); registerRoute( ({ request }) => { const { destination } = request; console.log("Service Worker:", "request", request); return destination === "video" || destination === "image"; }, ({ event, request }) => { // console.log("Service Worker: in the 2nd param", event, request); event.respondWith(async () => { await addToCache(request.url); return cacheFirstStrategy.handle({ request }); }); } );
1. 修复registerRoute的处理函数错误
你在registerRoute的第二个参数里手动调用event.respondWith是错误的——Workbox的路由处理函数不需要自己调用respondWith,它会自动处理。这种写法会导致Workbox逻辑失效,路由根本不会触发。
修改为符合Workbox规范的写法:
registerRoute( ({ request }) => { const { destination } = request; console.log("Service Worker:", "request", request); return destination === "video" || destination === "image"; }, async ({ request }) => { await addToCache(request.url); return cacheFirstStrategy.handle({ request }); } );
或者更简洁的方式(CacheFirst会自动缓存成功响应,无需额外addToCache):
registerRoute( ({ request }) => request.destination === "video" || request.destination === "image", cacheFirstStrategy );
2. 修正install事件的日志错误
你的install事件日志描述错误,同时可以加上skipWaiting确保新SW立即激活:
self.addEventListener("install", (event) => { console.log('Service worker: install event', event); event.waitUntil(self.skipWaiting()); });
3. 移除注册后立即更新的逻辑
注册成功后立刻调用registration.update()会触发SW更新检查,可能导致新SW进入等待状态,旧SW仍控制页面,新路由逻辑无法生效。移除这行代码,或在用户交互时手动触发更新:
// main.js中修改注册逻辑 navigator.serviceWorker.register(`/sw.js`) .then((registration) => { console.log("Service worker registered!"); navigator.serviceWorker.ready.then(() => { console.log('Service Worker: ready'); }); })
4. 验证请求范围与destination字段
确保图片/视频请求在SW作用域内(顶级作用域下,所有同源请求都应被拦截),同时在路由匹配函数中打印request.destination,确认其值确实为image或video(部分第三方资源或特殊请求的destination可能为empty)。
5. 检查Workbox模块导入
确认构建工具(如Webpack)正确处理了Workbox的ES模块导入,若有问题可改用Workbox CDN脚本导入,避免模块加载失败导致代码不执行。
内容的提问来源于stack exchange,提问作者john

