网站无故缓存问题修复及Service Worker优化方案
问题解决与Service Worker优化方案
一、修复当前缓存问题
1. 调整Express静态文件缓存头
你的express.static默认会给静态资源设置Cache-Control头,可能和Cloudflare的缓存策略冲突,导致旧资源被持久缓存。修改托管代码,强制禁用浏览器缓存并开启ETag校验:
app.use("/path", express.static(path, { maxAge: 0, // 禁止浏览器本地缓存 etag: true, // 开启ETag,让Cloudflare能校验资源是否更新 lastModified: true // 配合Last-Modified头做缓存有效性校验 }));
2. 修正Cloudflare缓存配置
- 全量清除缓存:执行「Purge Everything」操作,确保Cloudflare所有节点的旧缓存完全清除,不要仅清理单个文件
- 细分缓存规则:
- 对HTML文件设置「缓存级别:忽略查询字符串」+「浏览器缓存TTL:0」,避免HTML被长期缓存
- 对带打包哈希的JS/CSS/图片等静态资源,设置「缓存级别:标准」+「浏览器缓存TTL:1年」,利用文件名哈希自动触发更新,同时最大化缓存效率
- 检查是否存在Page Rules覆盖了默认缓存策略,比如某些路径设置了「缓存一切」导致旧资源无法更新
3. 临时强制客户端刷新
对于已访问过站点的用户,可在HTML头部添加脚本,检测资源版本差异时自动强制刷新:
<script> // 替换{{assetVersion}}为实际的打包版本号(比如React打包后生成的哈希) if (localStorage.getItem('assetVersion') !== '{{assetVersion}}') { localStorage.setItem('assetVersion', '{{assetVersion}}'); window.location.reload(true); // 强制从服务器拉取最新内容 } </script>
二、Service Worker优化方案
1. 核心优化点
(1)动态获取缓存资源
不要手动维护缓存URL列表,改用React打包生成的asset-manifest.json自动同步需要缓存的资源:
const cacheVersion = 3; const cacheName = `cache-${cacheVersion}`; const manifestUrl = '/asset-manifest.json'; self.addEventListener('install', event => { event.waitUntil( fetch(manifestUrl) .then(res => res.json()) .then(manifest => { const assets = Object.values(manifest.files); return caches.open(cacheName).then(cache => cache.addAll(assets)); }) ); });
(2)分类型缓存策略
针对不同资源类型使用适配策略,平衡更新及时性与加载速度:
self.addEventListener('fetch', event => { const request = event.request; // HTML文件:网络优先,确保用户看到最新内容,缓存仅作离线备用 if (request.mode === 'navigate' || request.destination === 'document') { event.respondWith( fetch(request) .then(networkRes => { caches.open(cacheName).then(cache => cache.put(request, networkRes.clone())); return networkRes; }) .catch(() => caches.match(request)) ); return; } // 静态资源:缓存优先,后台静默更新缓存 if (request.method === 'GET' && !request.url.includes('/api/')) { event.respondWith( caches.match(request) .then(cacheRes => { // 后台请求更新缓存,不影响当前页面加载 const updatePromise = fetch(request).then(networkRes => { caches.open(cacheName).then(cache => cache.put(request, networkRes.clone())); return networkRes; }); return cacheRes || updatePromise; }) ); return; } // 其他请求(API、POST等)直接走网络 event.respondWith(fetch(request)); });
(3)自动通知用户更新
当Service Worker更新完成后,主动通知用户刷新页面,确保新缓存立即生效:
self.addEventListener('activate', event => { event.waitUntil( Promise.all([ // 删除所有旧版本缓存 caches.keys().then(cacheNames => { return Promise.all( cacheNames.filter(cache => cache !== cacheName).map(cache => caches.delete(cache)) ); }), // 立即接管所有打开的客户端页面 self.clients.claim(), // 向所有客户端发送更新通知 self.clients.matchAll().then(clients => { clients.forEach(client => { client.postMessage({ type: 'SW_UPDATED' }); }); }) ]) ); }); // 前端页面监听更新通知 if ('serviceWorker' in navigator) { navigator.serviceWorker.addEventListener('message', event => { if (event.data.type === 'SW_UPDATED') { if (confirm('站点已更新,是否刷新页面获取最新内容?')) { window.location.reload(); } } }); }
内容的提问来源于stack exchange,提问作者Moodo9
相关产品推荐
相关产品推荐

