一张表看懂 HTTP 缓存:到底谁说了算
做站的人迟早会遇到这个场景:本地改完 CSS,刷新一看没变;或者明明发了新版,别人打开还是老样子,还截图来问你。
十有八九是缓存。而缓存这件事,浏览器其实很听话——你说能存多久,它就存多久。问题通常出在头没写对,或者写了但和文件名对不上。
两种缓存,别混在一起
强缓存:压根不发请求。浏览器看本地还没过期,直接用。
协商缓存:发一个很轻的请求去问服务器“我这份还能用吗”。能用就回 304,不带内容;不能用才回 200 和新文件。
一个省流量,一个省带宽但省不了往返。实际项目里,两者是搭配用的。
强缓存:管“多久不用问”
Cache-Control: max-age=2592000, immutable
意思是 30 天内别来问我,而且我保证这期间内容不会变(immutable)。
老一点的写法是 Expires,给一个绝对时间:
Expires: Wed, 21 Oct 2026 07:28:00 GMT
Cache-Control 优先于 Expires。现在没必要再用 Expires 了,除非你要兼容很老的客户端。
还有两个容易忽略的修饰:
s-maxage=600:只对 CDN、反向代理这类共享缓存生效,优先级高于max-age。public/private:能不能被共享缓存存。带登录信息的响应应该用private。
协商缓存:管“过期了怎么办”
过期之后不是直接重下,而是先问一句。
服务器第一次返回时给个指纹:
ETag: "a1b2c3"
Last-Modified: Sat, 17 Oct 2026 09:12:00 GMT
浏览器下次带上:
If-None-Match: "a1b2c3"
If-Modified-Since: Sat, 17 Oct 2026 09:12:00 GMT
服务器一比对,没变就回 304 Not Modified,响应没有 body,只有几十字节的头。变了才回 200 加新内容。
ETag 比 Last-Modified 准。原因是时间只精确到秒,而且文件内容没变、只是被重新保存一次,Last-Modified 也会变。所以两个都有时,ETag 优先。
一张表
| 指令 | 作用 | 典型值 |
|---|---|---|
max-age | 强缓存多久,单位秒 | 31536000(一年) |
s-maxage | 共享缓存多久,覆盖 max-age | 86400 |
no-cache | 可以存,但每次用之前必须问 | — |
no-store | 完全不许存 | 支付、隐私页 |
must-revalidate | 过期后不许拿旧的凑合 | — |
immutable | 有效期内绝不重新验证 | 带指纹的静态资源 |
private | 只有浏览器能存,CDN 不行 | 登录后的页面 |
public | 谁都能存 | 公共静态资源 |
no-cache 这个名字特别容易误解:它不是“不缓存”,而是“存可以,但用之前必须问”。真不想存,用 no-store。
静态资源:一年 + 指纹
CSS、JS、图片这类东西,最省事的组合是:
- 文件名里带内容哈希,比如
main.a1b2c3d4.css; - 响应头给一年 +
immutable。
Cache-Control: public, max-age=31536000, immutable
内容一变,哈希就变,文件名就变,浏览器自然会当成新文件去取。旧文件没人引用,CDN 到期自己就清了。用哈希换缓存,是这里最关键的一步——不带指纹的文件名不要配长缓存,否则你改完用户一年都看不到。
HTML:永远别长缓存
HTML 是入口,它决定引用哪个版本的资源,所以它必须能被及时更新。
Cache-Control: no-cache
配合 ETag,正常情况就是一个 304,成本很低。
常见的坑是:HTML 长缓存了,里面还引用着旧哈希的 CSS——用户清了缓存也没用,因为拿到的新 HTML 又指回旧文件。长缓存只能给带指纹的资源,不能给入口页。
几个容易踩的点
- 刷新行为不一样:普通刷新(F5)通常会跳过强缓存去验证,强制刷新(Ctrl+Shift+R)会连缓存一起清。所以“我这边刷新是好的”不能证明用户那边没问题。
Vary没写:同一 URL 返回不同内容(比如按Accept-Encoding或语言),共享缓存可能把 A 的响应给 B。至少写Vary: Accept-Encoding。- CDN 有自己的一层:源站的
Cache-Control不一定被完全尊重,有的 CDN 会按自己的规则覆盖。排查时先看响应头里到底是哪一层加的。 304也会更新缓存时间:拿到304后,浏览器会把这份缓存的有效期重新算一遍。
一句话总结:给带指纹的资源长缓存,给 HTML 短缓存,剩下的事情交给 ETag。 三句话能解决九成的“改了看不到”。