一句话定义:HTTP 缓存语义(HTTP caching semantics)是一套写在响应头里的约定,用来回答两个问题——这份内容能存吗、能存多久?过了这段时间,又凭什么判断它还能不能接着用。前者归 Cache-Control 管,后者主要靠 ETag。
打个比方:保质期和验货电话
把服务器上的资源想成一份文件。浏览器、CDN 节点(内容分发网络,Content Delivery Network)都是拿着复印件的分发点。
Cache-Control: max-age=3600 就像贴在复印件上的保质期标签:一小时内,这份复印件可以直接用,别打电话问了。这段叫新鲜期(freshness),命中时零网络往返,快得没有道理可讲。
过了保质期,复印件不一定坏了,只是不能再拍胸脯保证。这时进入验证阶段(validation):浏览器带上 If-None-Match: <那个 ETag> 去问服务器"我手里这版还有效吗?"服务器比对后:
- 没变 → 返回
304 Not Modified,一个只有响应头、没有正文的空回复,浏览器把本地副本重新标记为新鲜,省下的是整个文件体积; - 变了 → 返回
200和新内容,顺带给一个新的ETag。
ETag(Entity Tag)就是服务器为某个版本打的指纹,内容一变,指纹就变。
几个最容易被搞错的指令
| 指令 | 真实含义 |
|---|---|
no-cache | 不是"不缓存",而是"每次用之前必须先验证" |
no-store | 真的一个字都不许留,任何一层都不许 |
s-maxage | 只管 CDN、代理这类共享缓存,优先级高于 max-age |
private / public | 决定能不能存进共享缓存;带登录态的接口默认不该被 CDN 存 |
immutable | 新鲜期内连用户点刷新都不用去验证 |
和相邻概念的区别
常被拿来替代 ETag 的是 Last-Modified,配套 If-Modified-Since。但它只精确到秒,而且内容改了又改回、或只动了不影响语义的部分,都可能误判,所以 ETag 更可靠。ETag 还分强弱,弱 ETag 以 W/ 开头,只承诺"语义等价"而非字节完全一致。
也可以这样对照:Cache-Control 定规则,ETag 做验证。
对实际工作的意义
- 打包产物(带内容哈希文件名的 JS、CSS、字体、模型权重分片)适合长
max-age加immutable,文件名一变自然就换了新地址,这是最省心的做法; - HTML 入口页和接口数据适合
no-cache或很短的max-age,保证能看到新版本; - 如果响应里什么缓存头都没有,浏览器会自行做启发式缓存,行为不可控,线上问题常常出在这里;
- 打开开发者工具的 Network 面板,若 Size 一列写着 from disk cache / from memory cache,说明命中新鲜期;看到 304,说明走了一次验证;
- 用户说的"清理一下缓存就好了",大多就是某一层缓存拿到了过期却没能正确验证的副本。
具体指令的完整定义和边界情况,以 MDN 与 HTTP 规范官方页面为准。
