HTTP 缓存
服务器
HTTP
Nginx
User: cache-control 的值有哪些 Kimi: Cache-Control 是 HTTP 缓存控制的核心响应头,其指令值分为请求指令和响应指令两类,可以组合使用。
HTTP 缓存
User: cache-control 的值有哪些 Kimi: Cache-Control 是 HTTP 缓存控制的核心响应头,其指令值分为请求指令和响应指令两类,可以组合使用。
常用指令值
| 指令 | 类型 | 含义 |
|---|---|---|
| no-cache | 通用 | 可以缓存,但每次使用前必须向服务器验证(协商缓存) |
| no-store | 通用 | 完全禁止缓存,不存储任何版本 |
| max-age=<秒> | 通用 | 缓存有效时长,单位秒。如 max-age=3600 = 1小时 |
| s-maxage=<秒> | 响应 | 仅对共享缓存(CDN/代理)生效,优先级高于 max-age |
| private | 响应 | 只能被浏览器缓存,代理/CDN 不得缓存 |
| public | 响应 | 任何缓存(浏览器、CDN、代理)都可以缓存 |
| must-revalidate | 响应 | 缓存过期后必须向服务器验证,不能用过期缓存 |
| proxy-revalidate | 响应 | 仅对共享缓存要求 must-revalidate |
| immutable | 响应 | 资源在 max-age 内绝对不会变,浏览器不必发验证请求 |
| no-transform | 通用 | 禁止代理/CDN 对资源进行压缩、转码等转换 |
| stale-while-revalidate=<秒> | 响应 | 过期后 <秒> 内可先用旧缓存,后台异步更新 |
| stale-if-error=<秒> | 响应 | 源站出错后 <秒> 内可继续用旧缓存 |
常见组合用法
| 场景 | 值 | 说明 |
|---|---|---|
| 完全禁用缓存 | no-cache, no-store, must-revalidate | 开发环境、敏感页面 |
| 静态资源长期缓存 | public, max-age=31536000, immutable | 带 hash 的 JS/CSS,1年不变 |
| 私有数据 | private, no-cache | 用户个人信息页 |
| CDN 缓存但浏览器不缓存 | public, s-maxage=3600, max-age=0 | CDN 缓存1小时,浏览器每次都验证 |
| 渐进式更新 | max-age=3600, stale-while-revalidate=86400 | 1小时内直接缓存,过期后1天内先用旧的后台更新 |
示例
nginx# 1. 完全禁用(API、管理后台) Cache-Control: no-cache, no-store, must-revalidate, private # 2. 长期缓存(带 hash 的静态资源) Cache-Control: public, max-age=31536000, immutable # 3. 短期缓存 + 后台更新(HTML 入口) Cache-Control: public, max-age=0, s-maxage=60, stale-while-revalidate=300 # 4. 仅 CDN 缓存(SSR 页面) Cache-Control: public, s-maxage=60, max-age=0, must-revalidate
与 Expires、Pragma 的关系
| 头部 | 优先级 | 说明 |
|---|---|---|
| Cache-Control | 最高 | HTTP/1.1,现代标准 |
| Expires | 中 | HTTP/1.0,绝对时间,如 Wed, 21 Oct 2026 07:28:00 GMT |
| Pragma: no-cache | 低 | HTTP/1.0 遗留,仅兼容旧系统 |
如果同时存在,Cache-Control 会覆盖 Expires。
组合后的实际效果
add_header Cache-Control "no-cache, no-store, must-revalidate, private";
这条 Nginx 配置是给 HTTP 响应添加 Cache-Control 头部,意思是完全禁止任何形式的缓存。逐词拆解:
| 指令 | 作用 |
|---|---|
no-cache | 可以缓存,但每次使用前必须向服务器验证(发协商缓存请求),不能直接拿来用 |
no-store | 彻底不存,不缓存任何版本到磁盘或内存 |
must-revalidate | 一旦过期(或验证失败),必须重新请求,不能用过期缓存"凑合" |
private | 只有浏览器能缓存,中间代理/CDN不允许缓存 |
plain浏览器: 不缓存(no-store)→ 每次都重新请求 CDN/代理:不缓存(private + no-store)→ 完全透传 服务器: 每次都要重新生成响应(SSR 执行)
结果:用户每次访问这个页面,都要完整走一遍服务端渲染,拿到最新内容。
为什么需要四个指令一起用?
单独用一个有漏洞:
| 只用 | 漏洞 |
|---|---|
仅 no-cache | 浏览器还是会存一份到本地,只是每次要验证 |
仅 no-store | 理论上够了,但旧 HTTP/1.0 代理不认识 |
仅 must-revalidate | 没有 no-store 时,代理可能先给旧缓存 |
仅 private | 浏览器还是会缓存 |
四个叠在一起 = 覆盖所有缓存层级(浏览器、CDN、代理、中间件),确保万无一失。
简单记忆
| 想要的效果 | 用什么 |
|---|---|
| 完全不要缓存 | private, no-cache, no-store, max-age=0, must-revalidate |
| 可以缓存但要实时验证 | no-cache |
| CDN 缓存但浏览器每次都问 | public, max-age=0 |
| 永久缓存不变资源 | public, max-age=31536000, immutable |