如何解决PWA缓存需要两次刷新才能展示最新内容的问题
问题根源
- 现有Service Worker的静态资源匹配规则存在语法错误,
/.*\.(?:css|js|scss|)/末尾的空匹配分支会将.php后缀的动态页面、不带后缀的路由请求都纳入StaleWhileRevalidate策略覆盖范围,该策略会优先返回缓存内容,后台异步更新缓存,所以首次刷新拿到旧内容,第二次才能拿到更新后的缓存。 - 动态HTML页面没有专属缓存策略,带用户身份的页面被全局缓存后,会出现跨账号内容泄露的问题。
修复方案
1. 修正静态资源匹配规则
给静态资源正则补充结束符$,避免误匹配动态页面请求:
把原来的静态资源路由正则从/.*\.(?:css|js|scss|)/改为/.*\.(?:css|js|scss)$/
2. 新增动态页面专属缓存策略
针对PHP返回的动态HTML内容,使用网络优先策略,正常情况优先拿服务器最新内容,离线时才回退缓存;如果要求100%实时,可直接使用NetworkOnly策略。
修改后的完整Service Worker代码
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js'); if (workbox) { console.log("Yay! Workbox is loaded !"); workbox.precaching.precacheAndRoute([]); /* 缓存others目录下的图片,可根据自己的目录配置调整 */ workbox.routing.registerRoute( /(.*)others(.*)\.(?:png|gif|jpg)/, new workbox.strategies.CacheFirst({ cacheName: "images", plugins: [ new workbox.expiration.Plugin({ maxEntries: 50, maxAgeSeconds: 30 * 24 * 60 * 60, // 30天 }) ] }) ); /* 缓存JS、CSS、SCSS静态资源,后台异步更新缓存 */ workbox.routing.registerRoute( // 修正正则,添加结束符避免匹配动态页面 /.*\.(?:css|js|scss)$/, new workbox.strategies.StaleWhileRevalidate({ cacheName: "assets", }) ); /* 新增:动态HTML页面走网络优先策略 */ workbox.routing.registerRoute( // 匹配所有HTML文档请求 ({request}) => request.destination === 'document', new workbox.strategies.NetworkFirst({ cacheName: "html-pages", networkTimeoutSeconds: 3, // 网络超时3秒后回退缓存 }) ); // 缓存谷歌字体 workbox.routing.registerRoute( new RegExp("https://fonts.(?:googleapis|gstatic).com/(.*)"), new workbox.strategies.CacheFirst({ cacheName: "google-fonts", plugins: [ new workbox.cacheableResponse.Plugin({ statuses: [0, 200], }), ], }) ); // 离线分析统计 workbox.googleAnalytics.initialize(); // 新Service Worker安装后立即生效 workbox.core.skipWaiting(); workbox.core.clientsClaim(); } else { console.log("Oops! Workbox didn't load"); }
额外注意事项
- 如果存在带用户身份的API接口,也需要给这类接口添加对应的
NetworkOnly策略,避免缓存用户敏感数据。 - 发布新的Service Worker后,用户端首次打开就会自动更新SW,生效后就不会再出现刷新两次才显示新内容、账号串用的问题。
内容的提问来源于stack exchange,提问作者shyju chathampalli
相关产品推荐
相关产品推荐

