Service Worker缓存CloudFront图片后仍发起网络请求的问题排查
我来帮你梳理下这个问题的可能原因和排查方向,你遇到的情况其实挺常见的,咱们一步步来拆解:
首先先明确几个关键点:你说缓存已经成功存储,但还是看到CloudFront的请求,而且Service Worker里的日志打不出来,还预期看到(disk cache)/memory cache标识——这里先纠正一个误区:Service Worker缓存的资源,在Network面板里不会显示成(disk cache),而是会标注(ServiceWorker),浏览器的HTTP缓存和Service Worker缓存是两个独立的存储区域,这点别搞混了。
接下来看具体问题:
1. 为什么看不到Service Worker里的日志?
这是新手常踩的坑!Service Worker的控制台和页面的控制台是分开的,你在页面F12打开的控制台看不到Service Worker里的console.log输出。你需要:
- 打开浏览器开发者工具的「Application」标签
- 在左侧找到「Service Workers」
- 点击你当前运行的Service Worker旁边的「Inspect」,打开专门的Service Worker控制台,这里才能看到你代码里的日志。
2. 请求有没有被Service Worker拦截到?
你的fetch监听条件是event.request.destination === 'image' && event.request.url.includes("cloudfront.net"),有可能这个条件没匹配到目标请求:
- 先在Service Worker的fetch监听最开头加一行全局日志:
然后刷新页面,看目标图片的请求有没有出现在日志里。console.log(`拦截到请求:destination=${event.request.destination},URL=${event.request.url}`); - 检查CloudFront的URL是否带HTTPS?有没有大小写问题?比如URL里是
CloudFront.net而不是小写的cloudfront.net? - 有些图片请求是通过
srcset、picture标签发起的,或者是CSS里的背景图,这类请求的destination是不是image?可以通过上面的日志确认。
3. 缓存匹配为什么失败?
caches.match(event.request)默认是严格匹配,包括请求的方法、Headers(比如Accept头)、URL的查询参数(比如CloudFront可能加的?v=xxx版本号),只要有一点不一样,就匹配不上,会触发网络请求。
你可以放宽匹配条件试试:
caches.match(event.request, { ignoreSearch: true, // 忽略URL里的查询参数 ignoreVary: true // 忽略响应头里的Vary差异 })
4. Service Worker的状态和作用域有没有问题?
- 确认Service Worker已经处于「Activated」状态,而不是「Installing」或「Waiting」,可以在Application标签的Service Workers里查看。
- 检查Service Worker的作用域:如果你的Service Worker是在子目录注册的,可能覆盖不到图片请求的路径(比如图片在根目录,Service Worker在
/sw/目录)。注册的时候可以显式指定作用域:// 页面里注册Service Worker的代码 navigator.serviceWorker.register('/sw.js', { scope: '/' });
给你修改后的示例代码
结合上面的排查点,调整后的fetch监听代码如下(记得在Service Worker控制台看日志):
const CACHE_NAME = 'image-cache-v1'; // 确保这个变量已经在你的Service Worker里定义了 self.addEventListener('fetch', event => { console.log(`拦截到请求:destination=${event.request.destination},URL=${event.request.url}`); if (event.request.destination === 'image' && event.request.url.includes("cloudfront.net")) { event.respondWith( caches.match(event.request, { ignoreSearch: true, ignoreVary: true }) .then(response => { console.log(`缓存匹配结果:${response ? '命中' : '未命中'}`); if (response) { return response; // 返回缓存的图片 } // 缓存未命中,请求网络并缓存 return fetch(event.request).then(networkResponse => { const responseClone = networkResponse.clone(); caches.open(CACHE_NAME).then(cache => { cache.put(event.request, responseClone); console.log(`已缓存新图片:${event.request.url}`); }); return networkResponse; }); }).catch(err => { console.error('网络请求失败且无缓存:', err); // 这里可以返回一张默认 fallback 图片,比如: // return fetch('/assets/fallback-image.png'); }) ); } });
最后,当Service Worker成功返回缓存的图片时,你会在Network面板的Size列看到(ServiceWorker)的标识,而不是你之前预期的(disk cache),这才是正确的状态。
备注:内容来源于stack exchange,提问作者Zach Anton

