强缓存
强缓存:浏览器自己判断资源是否在有效期内,直接使用本地副本,不发请求。
#tech / dev / frontend
#type / concept
#status / evergreen
#platform / browser
#tech / network
[!info] related notes
- 所属 MOC: 浏览器缓存体系
- 分类总览: 浏览器缓存分类与 304 / memory cache / disk cache
- 关联概念: 协商缓存, Age、Date 与新鲜度计算, Vary 与缓存键, Pragma 遗留兼容, 缓存失效与部署策略, CDN 边缘缓存
强缓存
强缓存:浏览器自己判断资源是否在有效期内,直接使用本地副本,不发请求。
核心机制
浏览器检查本地缓存是否”新鲜”(fresh):
- 新鲜:直接返回本地副本,状态码
200 from cache - 不新鲜:进入协商缓存流程
新鲜度计算
浏览器根据 max-age 和 Age 头部计算剩余新鲜时间:
freshness_lifetime = max_age - age - response_delay
max-age:缓存有效时长(秒)age:响应在缓存中已存在的时间(代理/CDN 添加)response_delay:浏览器到上一跳的网络延迟
详见 → Age、Date 与新鲜度计算
控制头
Cache-Control(现代主流)
Cache-Control: max-age=3600 # 3600 秒内直接用
Cache-Control: public # 允许 CDN/代理缓存
Cache-Control: private # 只有浏览器能缓存
Cache-Control: immutable # 有效期内绝不会变
Expires(HTTP/1.0 遗留)
Expires: Wed, 08 Apr 2026 12:00:00 GMT
优先级:Cache-Control > Expires > 启发式缓存(当两者都不存在时,浏览器可能用 Last-Modified 猜测新鲜度)
Cache-Control 指令速查
响应指令
| 指令 | 含义 |
|---|---|
max-age=<seconds> | 缓存有效时长(秒) |
s-maxage=<seconds> | 仅共享缓存(CDN/代理)使用的有效时长,浏览器忽略,优先级高于 max-age |
public | 允许任何缓存节点存储 |
private | 只允许浏览器私有缓存 |
immutable | 有效期内内容不会变化 |
no-cache | 可缓存,但用前必须验证(不是不缓存!) |
no-store | 不存储(真正的不缓存) |
must-revalidate | 过期后必须重新验证,不能使用过期副本 |
proxy-revalidate | 类似 must-revalidate,但仅对共享缓存生效 |
stale-while-revalidate | 过期后先返回旧缓存,同时后台更新 |
stale-if-error | 更新失败时允许用过期副本 |
no-transform | 代理不得修改响应体(如图片压缩、转码) |
请求指令
| 指令 | 含义 |
|---|---|
no-cache | 强制重新验证(浏览器强刷时发送) |
max-age=0 | 等价于强刷,要求缓存立即过期 |
only-if-cached | 只使用缓存,不发网络请求(离线模式) |
no-store | 请求和响应都不可缓存 |
[!tip] 浏览器强刷(
Ctrl+Shift+R)发送的请求头通常同时包含Cache-Control: no-cache和Pragma: no-cache。
no-cache vs no-store(最常见误区)
| 指令 | 行为 |
|---|---|
no-cache | 可以缓存,但每次使用前必须去服务器验证 |
no-store | 连存都别存,真正的不缓存 |
记忆口诀:no-cache 是”存可以,直接用不行”;no-store 是”连存都别存”。
stale-while-revalidate 详解
Cache-Control: max-age=60, stale-while-revalidate=300
时间线:
- 0-60 秒:新鲜,直接用缓存
- 60-360 秒:已过期,但浏览器仍然返回旧缓存,同时在后台发起验证请求
- 360 秒后:必须同步验证,不能再用旧缓存
这是很多 CDN 和前端框架(Next.js、Nuxt)使用的模式——用户永远不等网络,代价是最多 5 分钟的旧数据。
stale-if-error 详解
Cache-Control: max-age=3600, stale-if-error=86400
- 正常情况:3600 秒内直接用缓存
- 过期后如果验证失败(网络错误、5xx):允许继续使用旧缓存最多 86400 秒(1 天)
适合对可用性要求高、对数据新鲜度容忍度较大的场景。
immutable 深入
Cache-Control: max-age=31536000, immutable
告诉浏览器:这个资源在整个有效期内绝对不会变。浏览器在用户主动刷新(F5)时也可以跳过重新验证。
浏览器支持:
- Firefox:支持
- Safari:支持
- Chrome:不支持(截至 2026 年),退化为普通
max-age行为
典型场景:带内容哈希的静态资源。详见 → 缓存失效与部署策略
典型应用场景
# 带 hash 的静态资源(长期缓存)
Cache-Control: public, max-age=31536000, immutable
# 图片(中期缓存)
Cache-Control: public, max-age=86400
# HTML 主文档(每次验证)
Cache-Control: no-cache
# 用户敏感数据(不缓存)
Cache-Control: no-store, private
性能优势
强缓存是性能最好的方式:
- 不发请求
- 零网络延迟
- 省带宽