如何使用Service Worker缓存axios GET响应及站点静态资源并实现增量更新
解决方案
核心逻辑
放弃通过修改缓存名称触发全量资源更新的方案,改用单资源新鲜度校验机制,结合服务端ETag/Last-Modified响应头实现增量更新,完全匹配需求:首次加载全量下载资源、重载时读本地缓存、仅修改过的资源才会重新拉取。
前置配置(服务端)
先确保所有需要缓存的资源(字体、图片、GET接口)配置了以下响应头,服务端默认一般会自动生成,不需要额外开发:
ETag:资源内容的唯一哈希标识,内容修改后自动变更Cache-Control: no-cache:注意不是no-store,这个配置是告诉浏览器/Service Worker可以缓存资源,但使用前必须向服务端校验资源是否新鲜
Service Worker 实现
核心采用stale-while-revalidate(缓存优先、后台异步校验更新)策略,不需要修改业务代码,也不需要每次更新资源就调整缓存名称。
1. 注册Service Worker
在页面入口代码中添加注册逻辑:
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => console.log('SW注册成功', registration.scope)) .catch(err => console.log('SW注册失败', err)); }); }
2. 编写sw.js核心逻辑
// 缓存名称仅在需要全量清空所有用户缓存时才修改 const CACHE_NAME = 'site-static-axios-v1'; // 定义需要缓存的静态资源类型,可按需扩展 const ALLOWED_STATIC_TYPES = ['image', 'font']; // 识别axios请求的标识头 const AXIOS_HEADER = 'X-Requested-With'; self.addEventListener('fetch', event => { const req = event.request; // 仅处理同域GET请求 if (req.method !== 'GET' || !req.url.startsWith(self.location.origin)) return; // 匹配需要缓存的资源:静态资源 + axios GET请求 const isTargetStatic = ALLOWED_STATIC_TYPES.includes(req.destination); const isTargetAxios = req.headers.get(AXIOS_HEADER) === 'XMLHttpRequest'; if (!isTargetStatic && !isTargetAxios) return; event.respondWith( caches.match(req).then(cachedRes => { // 后台发起资源校验请求 const fetchPromise = fetch(req).then(networkRes => { // 仅当资源有更新(返回200)时才覆盖本地缓存 if (networkRes.status === 200) { caches.open(CACHE_NAME).then(cache => { cache.put(req, networkRes.clone()); }); } return networkRes; }); // 有缓存直接返回给页面,无缓存则等待网络请求结果 return cachedRes || fetchPromise; }) ); }); // 激活SW后立即控制所有已打开的页面 self.addEventListener('activate', event => { event.waitUntil(self.clients.claim()); });
运行效果说明
- 首次加载:无缓存,所有资源正常下载并存入缓存
- 页面重载:直接读取本地缓存返回,无重复下载
- 资源更新后:用户下次打开站点时,SW后台发起校验请求,未修改的资源服务端返回304无内容响应,不占用带宽;修改过的资源返回200完整内容,SW自动更新本地缓存,用户下一次访问就会加载新版本
可选优化
- 对于高频更新的静态资源,可以在文件名中加入内容哈希(比如
font.7a2f9b.woff2),文件名变更后SW会自动识别为新资源缓存,完全不会出现旧资源残留问题 - 可以在SW激活逻辑中加入缓存清理规则,定期删除超过90天未访问的资源,避免占用用户存储空间
内容的提问来源于stack exchange,提问作者Alixsep
相关产品推荐
相关产品推荐

