我本来只想看两分钟的页面,结果一转眼就被缓存的“魔法”耍得晕头转向。起先以为是自己要求高——刷新了好几次、清了浏览器缓存、换了手机浏览器,页面依旧在“...
我本来只想看两分钟,结果我以为是我要求高,后来才懂91网页版的缓存管理逻辑(细节决定一切)
我本来只想看两分钟的页面,结果一转眼就被缓存的“魔法”耍得晕头转向。起先以为是自己要求高——刷新了好几次、清了浏览器缓存、换了手机浏览器,页面依旧在“旧版本”和“新版本”之间打转。后来细看开发者工具,才慢慢拼出91网页版的缓存管理逻辑:不是谁错了,而是多个缓存层级协同工作,细节决定体验。

我把观察和结论整理成几部分,供有同样困惑的人参考。
一、我看到的症状(快速回顾)
- 页面静态资源更新了,但客户端仍然加载旧样式或脚本。
- 明明刷新了,网络请求返回的是cached (200) 或 304。
- 在无痕模式下或换网络环境能看到新版本,怀疑是本地缓存问题。
二、实测发现的缓存层级(从边缘到客户端)
- CDN/Edge Cache:对静态文件做长时间缓存(max-age 很大),提高分发效率。
- 浏览器HTTP缓存:根据响应头(Cache-Control、Expires、ETag、Last-Modified)决定是否重新拉取或复用本地缓存。
- Service Worker Cache:存在自定义缓存策略(cache-first、stale-while-revalidate)并能拦截网络请求,离线优先或加速体验。
- 应用级缓存:localStorage / IndexedDB 用于持久化一些业务数据或预渲染内容,刷新不会影响它们。
- 版本化策略:对不可变资源使用指纹(hash)命名;对可变资源通过短TTL或动态刷新策略管理。
三、如何定位问题(我用的步骤) 1) 开发者工具 → Network:勾选 Disable cache,再刷新,观察真实请求。 2) Network 面板看响应头:关注 Cache-Control、ETag、Last-Modified、Age、Via。 3) Application 面板:查 Service Workers、Cache Storage、IndexedDB,看看是否有缓存条目没更新。 4) 用 curl -I URL 或 wget --server-response 查看服务器响应头,排查 CDN 层。 5) 临时解决:hard reload(Ctrl+F5 / Shift+刷新)、清除站点数据、注销 service worker。
四、常见且有效的缓存策略(原理与实践)
- 静态不可变资源(带 hash):Cache-Control: public, max-age=31536000, immutable。更新时靠文件名变化使旧缓存自然失效。
- 动态或频繁更新资源:Cache-Control: no-cache 或短的 max-age;结合 ETag/Last-Modified 做协商缓存(304)。
- 离线体验/性能关键脚本:通过 Service Worker 做 stale-while-revalidate:先返回缓存(快),后台刷新更新缓存,下次生效。
- 部署时保证版本切换顺利:Service Worker 技术上要在新版本激活时做 skipWaiting + clients.claim 或用页面通知用户刷新。
五、实用命令/片段(快速上手) 查看响应头: curl -I https://example.com/path
简单的 Service Worker cache-first 策略(伪代码): self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request).then(resp => { const fetchPromise = fetch(event.request).then(networkResp => { if (networkResp && networkResp.status === 200) { caches.open('v1').then(cache => cache.put(event.request, networkResp.clone())); } return networkResp; }); return resp || fetchPromise; }) ); });
服务器端设置示例(静态资源): Cache-Control: public, max-age=31536000, immutable (可变资源): Cache-Control: public, max-age=60, must-revalidate
六、给开发者和普通用户的实用建议
- 开发者:对不可变资源使用文件指纹,动态内容用短TTL或协商缓存;service worker 更新策略一定要和部署流程同步,避免“旧SW拦截新请求”。
- 普通用户/测试人员:遇到旧内容频繁出现,先用 Disable cache 的开发者工具或无痕模式验证;必要时在 Application → Clear storage 清除站点数据或在浏览器设置里注销 service worker。
最后感慨一句:你本来只想看两分钟,但这两分钟足够看到一个产品在性能、离线和更新策略上做的权衡。很多时候问题不是“谁错了”,而是“哪里做了取舍”。真正解决体验差异的,恰恰是这些看不见但精心设计的细节。
相关文章
