HTTP 缓存语义

用 Cache-Control、ETag 与 Vary 表达缓存策略:公共缓存与私有缓存分层,命中校验走 304;缓存键未覆盖的维度变化会产生错误内容。

HTTP 缓存语义

HTTP 缓存通过响应头表达可缓存性与过期策略,让浏览器、CDN 与网关在不回源的情况下返回内容。Cache-Control 决定缓存位置与有效期,ETag 与 Last-Modified 支持条件请求,命中校验时服务端返回 304,客户端复用本地副本,只付一次往返的代价。

缓存键为什么重要

缓存键由请求方法、路径以及 Vary 指定的头部共同决定。键未覆盖的维度一旦变化就会返回错误内容,典型事故是忽略了语言、编码或租户维度的差异,导致用户看到错误的语言版本;更严重的是带鉴权的响应被共享缓存存储,造成跨用户数据泄露。

常用响应头

常用响应头
Cache-Control: public, max-age=3600, stale-while-revalidate=60
ETag: "v7"
Vary: Accept-Encoding, Accept-Language

# public 允许共享缓存;private 只允许浏览器缓存
# no-cache 每次都要校验;no-store 完全禁止存储

基本信息

强缓存由 max-age 与 s-maxage 决定有效期,期间不回源
协商缓存ETag 与条件请求配合,未变更返回 304
共享与私有public 允许共享缓存,private 仅限浏览器
失效控制no-store 禁止存储,no-cache 要求每次校验

典型使用场景

  • 静态资源:文件名带内容指纹,配长时间缓存
  • 接口响应:对变化不频繁的查询设置短缓存
  • CDN 边缘缓存:就近返回内容,降低回源带宽
  • 条件请求:大文件断点续传与增量更新
  • 灰度与回滚:通过版本化路径绕过旧缓存

怎么验证缓存生效

看响应头里的缓存命中和回源统计,而不是靠响应时间猜测。首次请求应为未命中并回源,第二次请求应命中缓存或返回 304;如果两次都回源,先检查请求是否携带了绕过缓存的头部、缓存键是否被额外维度打散,以及响应是否被声明为禁止存储。上线前用灰度和带指纹的资源路径验证,可以避免缓存错误内容被大面积分发。

带鉴权的响应默认不应被共享缓存存储:显式配置为私有或禁止存储,否则一旦被边缘节点缓存,其他用户可能拿到不属于自己的数据。

易错点

  • 缓存键未包含语言或编码维度,用户看到错乱内容
  • 私有数据被共享缓存存储,造成跨用户信息泄露
  • 静态资源不带指纹却设置了长时间缓存,发版后用户拿到旧文件
  • 发布时只改文件名不改缓存头,回滚后浏览器仍命中错误版本

数据来源与参考

  • RFC 9111:HTTP Caching
  • MDN Web 文档:HTTP 缓存
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌