PWA缓存异常:Chrome缓存占用达500MB,请求排查原因及解决方法
我之前帮朋友排查过类似的PWA缓存膨胀问题,结合你的描述,大概率是这几个原因导致的,咱们一步步拆解:
可能的诱因
1. 动态缓存没做任何限制,啥都往里塞
你用的「优先缓存,回退网络」策略,如果fetch事件里没做过滤,只要是网络返回的资源就往DYNAMIC_CACHEABLE_ASSETS里加,那麻烦就来了——比如用户反复打开的高清大图、接口返回的超大JSON数据,甚至不小心缓存了POST请求的响应(比如带大文件上传的返回),这些都会疯狂占空间。而且安卓设备系统层面有缓存上限,会自动清理溢出的部分,但Chrome桌面版默认缓存配额高很多,不会主动清,所以差距就出来了。
2. 旧缓存版本没清理,越积越多
你有没有在activate事件里处理旧缓存?如果每次部署更新了STATIC_CACHE_VERSION,但没删掉旧的静态缓存,那每次上线都会新增一份缓存,旧的还留在那。另外,serviceworker-webpack-plugin生成的serviceWorkerOption.assets会不会偷偷包含了source map文件?这些文件体积超大,要是被缓存了,分分钟占几十上百MB。
3. fetch逻辑没过滤不必要的请求
比如你是不是把第三方资源(比如广告图、统计脚本)也缓存了?或者没过滤大文件(比如视频、压缩包)?这些资源本来就不该进缓存,要是不小心加进去了,缓存大小肯定会爆炸。
4. 别被Chrome DevTools的显示坑了
虽然概率不大,但可以确认下DevTools里的「Cache Storage」是不是只展示了你应用域名下的缓存,有时候会混进其他站点的缓存数据,不过你安卓端只有20MB,这个可能性比较低。
对应的解决办法
给动态缓存加“刹车”:大小限制+过期清理
写个简单的缓存修剪函数,每次加新资源前检查总大小,超过阈值就删掉最老的条目:
const DYNAMIC_CACHE_MAX_SIZE = 50 * 1024 * 1024; // 设个50MB上限 function trimDynamicCache(cacheName, maxSize) { caches.open(cacheName).then(cache => { cache.keys().then(keys => { if (keys.length > maxSize) { // 删除最旧的缓存,递归直到符合大小限制 cache.delete(keys[0]).then(() => trimDynamicCache(cacheName, maxSize)); } }); }); }
然后在fetch事件里,把资源加入缓存后调用这个函数。同时,只缓存GET请求,POST/PUT这些非幂等请求的响应绝对不能缓存,还要过滤掉大文件(比如后缀是.mp4/.zip的)。
在activate事件里彻底清理旧缓存
每次Service Worker激活时,删掉所有和当前版本不匹配的缓存:
self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.filter(name => { // 保留当前静态缓存和动态缓存,其他全删 return name !== STATIC_CACHE_VERSION && name !== DYNAMIC_CACHEABLE_ASSETS; }).map(oldCache => caches.delete(oldCache)) ); }) ); });
记得每次静态资源更新时,一定要修改STATIC_CACHE_VERSION的值(比如从static-v1改成static-v2),这样激活事件才会触发清理。
严格过滤要缓存的资源
在fetch事件开头加几道关卡,只让必要的资源进缓存:
self.addEventListener('fetch', event => { // 跳过非GET请求 if (event.request.method !== 'GET') return; // 跳过第三方资源(如果不需要缓存的话) if (!event.request.url.startsWith(self.location.origin)) return; // 跳过大文件类型 const forbiddenExtensions = ['.mp4', '.zip', '.tar']; if (forbiddenExtensions.some(ext => event.request.url.includes(ext))) return; // 你的缓存逻辑 event.respondWith( caches.match(event.request).then(cachedRes => { const fetchRes = fetch(event.request).then(networkRes => { caches.open(DYNAMIC_CACHEABLE_ASSETS).then(cache => { cache.put(event.request, networkRes.clone()); trimDynamicCache(DYNAMIC_CACHEABLE_ASSETS, DYNAMIC_CACHE_MAX_SIZE); }); return networkRes; }); return cachedRes || fetchRes; }) ); });
检查serviceWorkerOption.assets里的资源
在sw.js的install事件里加个打印,看看serviceWorkerOption.assets到底包含了啥:
console.log('[sw] 即将缓存的静态资源:', serviceWorkerOption.assets);
要是发现有source map或者其他超大文件,就在webpack的serviceworker-webpack-plugin配置里用exclude选项把它们排除掉,别让这些冗余资源占缓存。
最后,你可以打开Chrome DevTools的「Application」→「Cache Storage」,挨个查看缓存条目大小,找到占空间最大的那个,这样就能精准定位问题根源了。
内容的提问来源于stack exchange,提问作者amdev

