网站加载慢?重复请求浪费带宽?用户总是看到旧版本?这些问题背后,都指向同一个关键词:缓存。今天我们从 HTTP 头开始,彻底搞懂强缓存、协商缓存、CDN 缓存、前端静态资源版本管理,以及最常见的缓存坑和解决方案。
缓存是 HTTP 协议中用于复用之前获取的资源的机制。合理使用缓存可以:
但缓存用不好,会导致用户看到过期内容,或者每次都重新下载,失去缓存意义。
强缓存由服务器返回的响应头中的 Cache-Control(HTTP/1.1)或 Expires(HTTP/1.0,已过时)控制。
| 指令 | 含义 |
|---|---|
max-age=3600 |
资源在 3600 秒内是 “新鲜的”,直接使用缓存,不请求服务器 |
no-cache |
跳过强缓存,但可以用协商缓存(见下文) |
no-store |
完全不缓存,每次都重新下载 |
public |
可以被任何中间节点(CDN、代理)缓存 |
private |
只能被浏览器缓存,不能给中间节点(如用户个人信息) |
immutable |
资源永不变化(通常配合带 hash 的文件名使用),浏览器不必再验证 |
浏览器请求资源 → 服务器返回资源 + Cache-Control: max-age=3600
→ 浏览器缓存该资源,3600秒内再次请求直接读缓存(200 from disk cache)
→ 3600秒后重新请求服务器
Cache-Control: max-age=0,告诉服务器不要用缓存,走协商缓存。Cache-Control: no-cache,强制重新下载。当强缓存过期,或者请求头带有 Cache-Control: no-cache 时,浏览器会发起协商缓存请求,询问服务器资源是否有更新。
服务器返回 Last-Modified(资源最后修改时间),浏览器下次请求带上 If-Modified-Since。服务器比对时间,若未修改则返回 304 Not Modified,浏览器使用缓存;若修改则返回 200 和新资源。
缺点:
ETag 是服务器根据文件内容生成的唯一标识(哈希值),更精确。浏览器下次请求带上 If-None-Match: "某hash"。若未变则返回 304,否则返回 200 和新资源。
优先级:ETag 高于 Last-Modified。
浏览器: 我有个资源,ETag是"abc",你变了没?
服务器: 没变,304,你继续用旧的
浏览器: (用缓存)
| 特性 | 强缓存 | 协商缓存 |
|---|---|---|
| 发起请求 | 不发(直接用缓存) | 发,但服务端不返回体 |
| 状态码 | 200 (from disk/memory cache) | 304 |
| 控制头 | Cache-Control / Expires | Last-Modified / ETag |
| 适用场景 | 不常变的静态资源(JS/CSS/图片) | 可能变化的 HTML、API 响应 |
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
注意:文件名必须带 hash(如 main.a3f2b1c.js),内容变化时 hash 变化,浏览器才会重新下载。这是目前最主流的前端静态资源缓存策略。
location ~ \.html$ {
add_header Cache-Control "no-cache";
}
因为 HTML 需要随时更新(入口文件),不能强缓存。
Cache-Control: no-cache
Cache-Control: max-age=60(短时缓存)常见于:
max-age=60)。CDN 是 “反向代理缓存”,缓存静态资源在全球边缘节点。配置时需注意:
Cache-Control: public 允许 CDN 缓存。max-age,太短会增加回源请求,太长会导致更新不及时。(memory cache)、(disk cache) 或状态码 304。Cmd+Shift+R (Mac) / Ctrl+F5 (Windows)| 坑 | 原因 | 解决 |
|---|---|---|
| 上线后用户还是旧版本 | HTML 被强缓存 | HTML 用 no-cache 或短时缓存 |
| CSS 改了,页面样式还是旧的 | CSS 文件名没变,浏览器强缓存 | 文件名加 hash |
| 图片更新了,还是旧图 | CDN 缓存未刷新 | 版本化 URL 或主动刷新 CDN |
| 304 请求多,还是慢 | 强缓存没开,每次都协商 | 给静态资源加 max-age |
| 场景 | 推荐配置 |
|---|---|
| 静态资源(带 hash) | Cache-Control: max-age=31536000, immutable |
| HTML 入口 | Cache-Control: no-cache |
| API(不变数据) | Cache-Control: max-age=60 |
| API(动态) | Cache-Control: no-cache |
| 用户头像等私有资源 | Cache-Control: private, max-age=3600 |
缓存策略没有 “标准答案”,需要根据业务需求权衡实时性和性能。但记住:带 hash 的静态资源放心强缓存,入口文件绝不强缓存。