有人发现了一个细节——91网 | 关于缓存设置的说法:关键点居然在这里!!据说后面还有更大的反转

前言 如果你在为网站速度和稳定性抓耳挠腮,91网最近的一次排查能给你启发。很多人把注意力放在 CDN、图片压缩、懒加载上,结果忽略了一个看起来不起眼但影响极大的细节——缓存标头(Cache headers)与变体(Vary)头的交互。这个小细节,恰好就是性能和缓存命中率的分水岭。
问题怎么出现的 在一次例行监测中,发现某些静态资源虽然已经上了 CDN,却频繁出现回源请求。直觉会指向 CDN 配置或回源性能,但用 curl -I 检查响应头后,真正的原因浮出水面:响应里既有 Cache-Control: public, max-age=31536000,又带了 Vary: Accept-Encoding,同时 ETag 在源服务器和 CDN 间表现不一致。更糟糕的,是部分动态生成的资源在 URL 后面附带无关查询字符串(例如 ?v=0),导致不同节点缓存碎片化。
为什么这是关键点
- Vary 头会告诉缓存服务器哪些请求头会影响响应内容。Vary: Accept-Encoding 意味着同一 URL 会根据请求是否支持 gzip/br 等返回不同内容,缓存需要分别存储。若 CDN/代理没有正确处理,缓存命中率会下降。
- ETag 和 Last-Modified 如果在源端和 CDN 之间不一致,条件请求(304)就起不了应有的作用,反而增加回源开销。
- 查询字符串与缓存策略不一致会让本该长期缓存的静态资源被频繁刷新,尤其是当缓存策略写得模糊时。
实战可操作的修复步骤 1) 逐一检查响应头:在浏览器 DevTools 的 Network 面板或用 curl -I 查看 Cache-Control、Expires、ETag、Last-Modified、Vary。把发现记录下来,定位问题来源是源站还是 CDN。 2) 简化 Vary:尽量减少 Vary 的使用。只有当响应确实根据特定请求头变化时才添加,例如 Vary: Accept-Encoding 是合理的,但如果资源始终以压缩形式统一交付,考虑在边缘层做统一处理来避免多份缓存。 3) 统一 ETag 策略:让源站和 CDN 对静态文件统一生成版本号(更推荐使用文件名/路径里直接带版本号,如 app.12345.css),减少 ETag 依赖。使用版本化文件名后,可以把 Cache-Control 设为 max-age=31536000。 4) 处理查询字符串:对 CDN 配置白名单策略,明确哪些查询参数会影响缓存;对于不影响内容的参数(如跟踪参数),让 CDN 忽略或统一处理。 5) 服务端和 CDN 的日志联动:当发现回源高时,对照访问日志和 CDN 控制台的缓存命中率,找到异常资源并优先修复。 6) 自动化验证:把头信息检查纳入持续集成或定期脚本,避免配置回退或误改带来性能倒退。
示例(Nginx 简单配置参考)
- 对静态资源启用长期缓存(配合版本化文件名): add_header Cache-Control "public, max-age=31536000, immutable";
- 对 HTML 页面: add_header Cache-Control "no-cache, must-revalidate";
别小看“细节” 很多团队把精力放在显眼的优化点,却忽视了缓存头与 CDN 之间的“契合度”。把这些头调好后,往往能在不改动前端代码的情况下,显著提升缓存命中率和网站响应速度。那所谓“更大的反转”是什么?接下来我会把一次看似完美的缓存策略如何被一个小插件、一个不经意的代理规则彻底推翻的完整案例写出来——结局比你想象的更具戏剧性。
如果你想,我可以为你的站点做一次快速的缓存与响应头诊断,帮你把那些藏在细节里的性能黑洞找出来。需要的话留下站点链接或头信息截图,我来分析。