Kailiming Blog

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=0CDN 缓存1小时,浏览器每次都验证
渐进式更新max-age=3600, stale-while-revalidate=864001小时内直接缓存,过期后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,现代标准
ExpiresHTTP/1.0,绝对时间,如 Wed, 21 Oct 2026 07:28:00 GMT
Pragma: no-cacheHTTP/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