看似偶然,其实是设计:91官网为什么有人用得很顺、有人总卡?分水岭就在缓存管理(建议收藏)

很多人会把网站“卡”或“流畅”归因于运气或网络波动,但实际背后常常是缓存策略在起作用。相同的页面,不同用户看到截然不同的响应速度,往往不是偶然,而是缓存命中(hit)或未命中(miss)造成的差异。本篇把缓存的原理、常见坑、诊断方法和可落地的优化建议都一并梳理,方便站长和普通用户快速定位与改善体验——收藏备用不会错。
一、为什么缓存能造成两类截然不同的体验?
- 缓存命中:资源由CDN或浏览器本地缓存直接返回,几乎零延迟(分钟级甚至毫秒级)。
- 缓存未命中:请求被回源到主机,涉及DNS、TLS握手、跨区域传输和后端渲染,延迟和失败率明显上升。
导致命中/未中差异的常见因素:
- 地理位置与CDN节点分布:邻近节点命中更高。
- 浏览器缓存状态:老用户可能已缓存大量静态资源,新用户则无缓存。
- 请求是否带有破坏缓存的标识(Cookie、Authorization、Vary: Cookie等)。
- 资源是否有版本指纹(fingerprint)或频繁改名/清除缓存。
- 服务端/CDN缓存策略(cache key、query string、cache-control、s-maxage 等)。
- 浏览器隐私设置或扩展导致缓存分区或阻止缓存。
- 动态/个性化内容无法走公共缓存。
二、核心技术点(快速理解)
- Cache-Control:最直接的缓存控制。常用策略示例:
- 静态资源:Cache-Control: public, max-age=31536000, immutable
- HTML 页面(需要快速更新):Cache-Control: s-maxage=60, stale-while-revalidate=30
- 非缓存(敏感页面):Cache-Control: no-store
- ETag / Last-Modified:用于校验资源是否变化,命中时通常返回 304 Not Modified。
- Vary 响应头:声明缓存区分的请求头(如 Vary: Accept-Encoding 或 Vary: Cookie)。Vary: Cookie 会显著降低共享缓存命中率。
- s-maxage:专门影响 CDN/共享缓存,优先于 max-age。
- stale-while-revalidate / stale-if-error:提高感知性能与鲁棒性,允许边返回旧内容边异步刷新。
- Cookie 与缓存:如果静态域带有 Cookie,会导致每次请求都带上 Cookie,从而降低CDN缓存命中并增加请求体积。
- 资源指纹化(hash 文件名):确保长期缓存同时能平滑发布新版本(避免主动清除全站缓存)。
三、常见坑与误区(会让“有人顺、有人卡”)
- 把所有东西都设置为 no-cache/no-store:结果每次都回源,体验打折。
- 在静态资源域名上设置 Set-Cookie:浏览器会携带 Cookie,使CDN缓存粒度下降。
- 使用 Vary: Cookie 或 Vary: Authorization:大幅降低缓存共享能力。
- 未对 HTML 做边界处理:完整禁止 HTML 缓存,会频繁回源。可用短 TTL + stale-while-revalidate 折衷。
- Service Worker 管理不当:老版本 SW 可能把旧资源长期缓存,导致部分用户看到不兼容内容或加载失败。
- CDN 配置错误(cache key 包括 query string、header、cookie 等不必要的字段):导致命中率下降。
- A/B 或灰度路由将用户分流到不同集群:部分集群缓存暖机不足,导致体验不均衡。
四、站长实战清单(优先级排序)
- 静态资源独立域名,去掉 Cookie
- static.example.com 或使用 CDN 子域,确保静态域不设置 Set-Cookie。
- 指纹化文件名 + 长缓存
- JS/CSS/图片等通过 hash 命名,Cache-Control: public, max-age=31536000, immutable。
- HTML 使用短 TTL + 边缘策略
- Cache-Control: public, s-maxage=60, stale-while-revalidate=30,这样用户看到页面更快,同时边缘刷新不阻塞响应。
- 优化 CDN cache key
- 仅保留必要的请求部分(path、必要查询参数)。避免不必要的 header/cookie 纳入 key。
- 使用 s-maxage 与 CDN Purge 协同
- 对于突发修复或紧急更新,可以基于版本化或发行策略做精准替换,避免全量清空缓存。
- 监控缓存命中率与热点节点
- 定期查看 CDN 的 hit/miss 指标,关注地理异常、不同运营商差异。
- 程序化缓存(边缘脚本 / ESI / 缓存分片)
- 将页面分为可缓存公共片段与个性化片段,减少回源压力。
- Service Worker 管控策略
- 明确 lifecycle:版本号、安装激活流程、回退策略与更新提示,避免导致部分用户卡在旧版本。
- 添加 stale-if-error
- 在不可预测的后端异常下,允许边缘返回旧内容以保证可用性。
- 打开压缩与 HTTP/2/3、TLS 调优
- 虽不是纯缓存问题,但能搭配缓存显著提升体验。
五、用户端快速诊断与临时改良方法
- 诊断:
- Chrome DevTools Network 面板,勾选 Disable cache,观察是否从 200/304 回来,查看响应头 Cache-Control/ETag/Vary。
- curl -I https://your.site 查看响应头。
- WebPageTest 或 Lighthouse 得到更全面的缓存与性能报告。
- 暂时改善:
- 清缓存或强制刷新(Ctrl+F5 / Shift+Reload)。
- 试用无痕/隐私模式(排除扩展或缓存隔离问题)。
- 切换网络(从移动数据切到 Wi‑Fi 或相反)看是否差异来自 ISP/CDN。
- 更新浏览器或禁用可能影响缓存的扩展(隐私或代理类扩展)。
六、举几个典型 header 配置示例(可直接参考)
- 静态资源(图片/JS/CSS)
- Cache-Control: public, max-age=31536000, immutable
- ETag: "xyz"
- HTML 页面(边缘缓存短时)
- Cache-Control: public, s-maxage=60, stale-while-revalidate=30
- Vary: Accept-Encoding
- 个性化接口(用户专属)
- Cache-Control: private, max-age=0, no-cache
七、结束语与速查清单(建议收藏)
- 若遇到“有人顺、有人卡”的问题,先从缓存命中率、Vary/Cookie、CDN 节点与服务端缓存策略入手排查。
- 最小化带 Cookie 的请求,指纹化静态资源,HTML 采用边缘短 TTL+stale 策略,结合监控与灰度发布,能在多数场景下把“卡”变成“顺”。
- 调试工具:Chrome DevTools(Network/Headers)、curl -I、WebPageTest、CDN 控制台的 hit/miss 报表、Lighthouse。
