Skip to content

HTTP 缓存进阶:Cache-Control、ETag、CDN 与最佳实践

缓存的目标:更快、更省流量、更稳。现代站点通常不只有“浏览器缓存”,还会有 CDN、反向代理等中间层,所以理解缓存要从“链路”出发。

先看图:强缓存 vs 协商缓存的命中路径

缓存流程:200/304 与强缓存/协商缓存

一句话记住:

  • 强缓存:没过期就直接用本地,不发请求
  • 协商缓存:会发条件请求(带指纹/时间),服务器可能返回 304

缓存不止浏览器:还有 CDN(中间层缓存)

常见链路:

  • 浏览器(memory/disk)
  • CDN/代理(共享缓存)
  • 源站(你的服务器)

同一个 URL,可能在不同层命中缓存。你在 DevTools 里看到的 200/304/from disk cache 只是浏览器层的表现;CDN 命中通常要看响应头(例如 AgeX-Cache 等,取决于平台)。

最重要的响应头:Cache-Control(优先级最高)

Cache-Control 决定“能不能缓存、缓存多久、是否需要重新校验”:

  • max-age=3600:强缓存 1 小时(浏览器层)
  • public / private:是否允许共享缓存(CDN/代理)缓存
  • s-maxage=3600:共享缓存(CDN)使用的强缓存时长(优先于 max-age)
  • no-cache:允许缓存,但每次都要协商(可能 304)
  • no-store:完全不缓存(敏感信息常用)
  • must-revalidate:过期后必须向服务器确认,不能直接用过期副本
  • immutable:资源在 max-age 内绝不会变(通常配合 hash 文件名)

Expires 是旧头,表达绝对时间;现在优先用 Cache-Control

协商缓存:ETag 与 Last-Modified

协商缓存有两套“对比方式”:

  • 基于内容指纹:ETagIf-None-Match
  • 基于修改时间:Last-ModifiedIf-Modified-Since

通常优先用 ETag(更准确)。如果资源没变:服务器返回 304 Not Modified,浏览器继续用本地文件。

缓存响应头速查

Vary:同一 URL 可能有“多个版本”

Vary 的作用是告诉缓存:同一个 URL 在不同请求头下可能返回不同内容。例如:

  • Vary: Accept-Encoding:gzip/br 压缩版本不同
  • Vary: Accept-Language:中英文内容不同

如果缺少正确的 Vary,就可能发生“拿到不属于你的缓存版本”的问题(例如语言错乱、内容不匹配)。

三类资源的推荐策略(最实用)

1) 带 hash 的静态资源(JS/CSS/图片)

目标:尽量命中强缓存,更新靠文件名变化。

txt
Cache-Control: public, max-age=31536000, immutable

2) HTML(入口页)

目标:更新要及时,避免用户拿到旧 HTML 指向旧资源。

txt
Cache-Control: no-cache

(含义:可以缓存,但每次都要协商确认。)

3) API 响应

如果包含用户隐私或登录态相关数据,优先:

txt
Cache-Control: no-store

如果是公共、可缓存的数据(例如文章列表),可以考虑短缓存 + 协商,或走 CDN(是否允许取决于业务与权限)。

如何在浏览器里验证(一步步排查)

打开 DevTools -> Network,点开某个请求:

  • Status200(新内容)或 304(复用本地)
  • Size:是否显示 from disk cache / from memory cache
  • 点开请求 -> Headers:查看 Cache-ControlETag
  • 勾选 “Disable cache” 只影响 DevTools 打开期间(排查缓存问题很有用)

一句话总结

缓存策略最稳的组合通常是:

  • 静态资源:文件名带 hash + 长强缓存
  • HTMLno-cache(或短 max-age
  • 接口:按业务决定是否缓存,敏感数据用 no-store

🎉有任何问题,欢迎联系我

WeChat QR Code
WeChat
QQ QR Code
QQ

感谢 Cloudflare 提供服务器支持