使用Workbox预缓存多页面/路由已生成缓存但无法匹配
问题解决:PWA离线访问/audits/edit失败
问题原因
- 预缓存资源被自定义路由策略覆盖:你通过
precacheAndRoute将/audits/edit等页面加入预缓存(存储在workbox-precache-*缓存组),但后续又给这些路径注册了NetworkFirst策略的路由,该策略使用独立的forms-home缓存组,离线时网络请求失败后,不会去预缓存中查找资源。 - 最后一条路由规则逻辑错误:
!['/audits/edit', '/audits/edit/'].includes(url)中的url是URL对象而非字符串路径,导致该条件永远为真,/audits/edit的请求会被这条路由匹配,而它使用的documents缓存组未缓存该页面,最终离线请求失败。
解决方案
- 移除针对
/和/audits/edit的自定义路由规则,让precacheAndRoute默认的CacheFirst策略处理这些页面,预缓存资源会直接从缓存读取,适配离线场景。 - 修正最后一条路由的匹配逻辑,将
url改为url.pathname,同时排除预缓存页面路径,避免冲突。 - 可选:添加全局兜底处理,当所有路由匹配失败时返回预缓存的根页面。
修改后的service_worker.js.erb代码
self.addEventListener('activate', event => { event.waitUntil(self.clients.claim()); }); importScripts("https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js") const {CacheFirst, NetworkFirst, StaleWhileRevalidate, CacheOnly} = workbox.strategies; const {registerRoute, setCatchHandler} = workbox.routing; const {warmStrategyCache} = workbox.recipes; const {precacheAndRoute} = workbox.precaching; const {CacheableResponsePlugin} = workbox.cacheableResponse; <% controllers = Dir.glob('app/javascript/controllers/**/*.js') %> precacheAndRoute([ {url: '/', revision: null}, {url: '/audits/edit', revision: null}, {url: '/templates/list-detail-index', revision: null}, {url: '/templates/list-detail-pdf', revision: null}, {url: '/templates/defect-card-edit', revision: null}, {url: '/templates/defect-card-pdf', revision: null}, {url: '/templates/defect-staged-image', revision: null}, {url: '<%= asset_path('application.js') %>', revision: null}, {url: '<%= asset_path('application.css') %>', revision: null}, {url: '/assets/utils/indexedDB', revision: null}, {url: '/assets/services/TemplateService', revision: null}, {url: '/assets/gateways/ClixifixAPI', revision: null}, {url: '/assets/utils/FileUtils', revision: null}, {url: '/assets/services/PDFService', revision: null}, {url: '<%= asset_path("exifr.js") %>', revision: null }, {url: '/assets/services/ExifService', revision: null}, {url: '/manifest.json', revision: null}, ], { ignoreURLParametersMatching: [/.*/], directoryIndex: null, } ); registerRoute( ({request}) => ['script', 'style', 'manifest', 'font'].includes(request.destination), new NetworkFirst({ cacheName: 'assets-styles-scripts', }) ); registerRoute( ({request}) => request.destination === 'image', new NetworkFirst({ cacheName: 'assets-images' }) ); // 修正路由匹配逻辑,排除预缓存页面路径 registerRoute( ({request, url}) => { const pathname = url.pathname; const excludedPaths = ['/', '/audits/edit', '/templates/list-detail-index', '/templates/list-detail-pdf', '/templates/defect-card-edit', '/templates/defect-card-pdf', '/templates/defect-staged-image']; return !excludedPaths.includes(pathname) && (request.destination === "document" || request.destination === ""); }, new NetworkFirst({ cacheName: 'documents', }) ); // 可选:全局兜底,请求失败时返回预缓存的根页面 setCatchHandler(async ({event}) => { switch (event.request.destination) { case 'document': return caches.match('/'); default: return Response.error(); } });
验证步骤
- 重新部署后,清除浏览器缓存并重新注册Service Worker。
- 在Chrome DevTools的
Application > Cache Storage中,确认workbox-precache-*缓存组包含/audits/edit页面。 - 切换离线模式,刷新根页面后点击A标签访问
/audits/edit,确认页面正常加载。
内容的提问来源于stack exchange,提问作者Mark Stephenson
相关产品推荐
相关产品推荐

