核心目的:减少网络请求、降低延迟、减轻服务器压力、节省带宽。 分为两大类:强缓存、协商缓存。
强缓存:不用发请求到服务器,直接拿本地缓存。 协商缓存:必须发请求给服务器,服务器判断缓存是否可用。
一、强缓存(不访问服务器,200 OK (from disk cache /from memory cache))
响应头控制,浏览器直接本地读取,不产生 HTTP 请求。
Expires: Wed, 10 Sep 2026 10:00:00 GMT
- 绝对时间,GMT 格式;受客户端系统时间影响,时间错乱会失效。
Cache-Control: max-age=86400
- max‑age=86400:缓存有效时长,单位秒。从响应返回那一刻开始计时。
常用指令:
| max‑age=N | 强缓存有效期 N 秒 |
| no‑cache | 不使用强缓存,强制走协商缓存 |
| no‑store | 完全不缓存,什么都不存 |
| public | 代理服务器也可以缓存(CDN) |
| private | 仅浏览器客户端缓存,CDN 不缓存 |
区分重点:
- no‑cache:不是不缓存,每次都要问服务器(协商缓存)
- no‑store:禁止一切缓存,本地不留副本
二、协商缓存(一定发请求到服务器,304 Not Modified)
浏览器带上标识,服务器对比资源有没有修改。
- 未修改:返回304 Not Modified,没有响应 body,浏览器直接读本地缓存
- 修改:返回200 OK,返回新资源
两套机制:
1. Last‑Modified / If‑Modified‑Since(基于修改时间)
1)服务器响应头返回:
Last‑Modified: Tue, 08 Sep 2026 08:00:00 GMT
资源最后修改时间。
2)下次请求,浏览器自动带上请求头:
If‑Modified‑Since: Tue, 08 Sep 2026 08:00:00 GMT
服务器对比文件修改时间:
- 时间没变 → 返回 304
- 文件更新 → 返回 200 + 新内容
缺点:
2. ETag / If‑None‑Match(基于内容哈希,优先级高于时间)
1)服务器返回资源哈希标识
ETag: "abc123xxxx"
ETag:资源内容的摘要哈希,内容一变 ETag 一定变。
2)浏览器下次请求带上
If‑None‑Match: "abc123xxxx"
服务器对比 ETag:
- 匹配:304
- 不匹配:200 返回新资源
ETag 解决 Last‑Modified 的秒级精度缺陷。
执行顺序(浏览器真实流程)
- ✅没过期:直接本地读取,from cache,不发 http 请求
- ❌过期了 → 进入协商缓存
- 服务器校验 ETag 优先,再校验修改时间
- 资源未改动 → 返回 304,浏览器用本地缓存
- 资源改动 → 返回 200,返回新资源,更新本地缓存副本
内存缓存 vs 磁盘缓存
- memory cache(内存):页面打开时存在内存,关闭标签页就释放;优先级高。
- disk cache(硬盘):写入硬盘,关闭浏览器还在。
JS、CSS、图片优先放内存;大文件进入磁盘缓存。
CDN 缓存
CDN 本质就是代理服务器缓存,遵循 HTTP 缓存头Cache‑Control。 静态资源放 CDN,设置合理 max‑age; 资源更新:修改资源文件名(加哈希后缀 app.abc123.js),绕过旧缓存。
HTTP 缓存默认开启吗?
✅浏览器端:默认开启 HTTP 缓存(强缓存 + 协商缓存全部默认打开) ❌后端服务器不会自动给你加缓存响应头,缓存生效,要看服务器返回的响应头
1、浏览器行为(客户端)
浏览器本身默认就会做缓存:磁盘缓存、内存缓存。 只要服务端返回了 Cache‑Control / Expires / Last‑Modified / ETag,浏览器就自动执行缓存逻辑,不需要前端写任何代码。
如果服务器什么缓存头都不返回: 浏览器依旧会试探性缓存(启发式缓存),不会完全不缓存,只是缓存时间不可控,不推荐靠这个。
启发式缓存
当响应既没有Cache‑Control:max‑age,也没有Expires。 浏览器拿 Date(响应时间) 和 Last‑Modified,自己算一个缓存时间(大概是差值的 10%)做短期强缓存。
不可控,业务不能依赖这个机制。
2、不同服务器默认行为
① Nginx、Apache(静态资源:图片 /js/css)
默认:
- 返回 Last‑Modified、ETag 👉 协商缓存默认生效
- 但是不会默认给你加 max‑age 强缓存,强缓存要手动配置。
也就是说 Nginx 静态文件:默认走协商缓存,会发请求,可能返回 304;不会直接 from disk cache。
② SpringBoot(Java 后端)
浏览器不会做有意义的缓存,每次都请求 200。 想要缓存,需要手动配置响应头,或者用@CacheControl,或者 WebMvc 配置。
3、怎么关闭浏览器缓存
4、总结
浏览器默认开启 HTTP 缓存能力; 协商缓存 (ETag/Last‑Modified) Nginx、SpringBoot 静态资源默认会返回; 强缓存 max‑age 不会默认开启,必须后端手动配置响应头; 如果服务端完全没有缓存头,浏览器会使用启发式缓存,行为不可预测。
补充示例 SpringBoot 开启缓存头
// 给响应设置强缓存,1天
response.setHeader("Cache‑Control","public,max‑age=86400");
生产实践: JS/CSS 图片 → Nginx 配置 max‑age 做大强缓存; HTML 页面一般不做强缓存,用 no‑cache 走协商缓存。

