CDN缓存策略与刷新
1. CDN 缓存层级
浏览器缓存 → CDN 边缘缓存 → CDN 中间层缓存 → 源站
每层都有独立的缓存时间:
- 浏览器:
max-age - CDN 边缘:
s-maxage(或 CDN 控制台规则) - 源站:真实数据
2. 缓存策略配置
2.1 源站响应头
# hash 静态资源(JS/CSS/图片)
Cache-Control: public, max-age=31536000, s-maxage=31536000, immutable
# HTML 入口
Cache-Control: public, max-age=0, s-maxage=60, stale-while-revalidate=300
# API 数据
Cache-Control: private, no-store
s-maxage 专门给 CDN / 中间代理:
max-age=60, s-maxage=3600:浏览器缓存 1 分钟,CDN 缓存 1 小时
2.2 CDN 控制台规则
优先级:控制台规则 > 源站头。
文件后缀 .js .css .woff2 → 缓存 365 天
文件后缀 .html → 缓存 0 秒(回源)
目录 /api/ → 不缓存
2.3 Vary 头
Vary: Accept-Encoding # gzip/br 分别缓存
Vary: Origin # 不同 CORS origin 分别缓存
Vary: User-Agent 是缓存杀手(几乎不命中),避免使用。
3. 刷新(Purge)
3.1 URL 刷新
精确清除单个 URL 缓存:
# 阿里
aliyun cdn RefreshObjectCaches --ObjectPath "https://cdn.example.com/index.html" --ObjectType File
# AWS
aws cloudfront create-invalidation --distribution-id E123 --paths "/index.html"
# Cloudflare
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer TOKEN" \
-d '{"files":["https://cdn.example.com/index.html"]}'
3.2 目录刷新
# 阿里(慢,配额少)
aliyun cdn RefreshObjectCaches --ObjectPath "https://cdn.example.com/assets/" --ObjectType Directory
# AWS
aws cloudfront create-invalidation --distribution-id E123 --paths "/assets/*"
3.3 全站刷新
# AWS
aws cloudfront create-invalidation --distribution-id E123 --paths "/*"
# Cloudflare
curl -X POST ".../purge_cache" -d '{"purge_everything":true}'
慎用:全站刷新 = 所有节点回源 = 源站瞬时压力大。
3.4 Cache Tag(Cloudflare / Fastly)
给资源打标签,按标签刷新:
Cache-Tag: product-123, homepage
curl -X POST ".../purge_cache" -d '{"tags":["product-123"]}'
最灵活,Fastly 实时生效(< 150ms)。
4. 预热(Prefetch / Prewarm)
刷新后主动让 CDN 节点拉取新资源:
# 阿里
aliyun cdn PushObjectCache --ObjectPath "https://cdn.example.com/app.abc123.js"
# 自定义脚本从各地区节点拉一次
for region in "us" "eu" "cn"; do
curl -H "Host: cdn.example.com" http://${region}-node.cdn.example.com/app.abc123.js > /dev/null
done
大文件 / 大促前预热避免首批用户回源。
5. stale-while-revalidate
Cache-Control: public, max-age=60, stale-while-revalidate=3600
过期后 1 小时内:返回旧缓存(快)+ 后台异步回源更新。
兼顾新鲜度和速度。CDN 和浏览器都支持。
6. stale-if-error
Cache-Control: public, max-age=300, stale-if-error=86400
源站挂了(5xx / 超时),CDN 返回旧缓存而非错误给用户。
生产必加:源站故障时用户仍能看到页面(虽然可能旧)。
7. 前端发版流程
1. 构建新版本 → app.NEW_HASH.js
2. 上传所有新文件到源站 / OSS(不删旧文件)
3. 部署新 index.html(引用新 hash)
4. 刷新 CDN 的 index.html
5. 预热关键资源(可选)
6. 7 天后清理旧版本文件
为什么保留旧文件:
- CDN 部分节点缓存旧 HTML(引用旧 JS)
- 用户浏览器缓存旧 HTML
- Service Worker 缓存旧 HTML
8. 回源率监控
回源率 = 回源请求 / 总请求。健康站点 < 5%。
高回源率排查:
1. Cache-Control 是否正确?
2. URL 是否每次不同(含时间戳/随机参数)?
3. Vary 头是否含 User-Agent?
4. 缓存 key 是否含不必要 query?
5. CDN 控制台规则是否覆盖了源站头?
9. CDN 控制台查看
CDN 状态:
X-Cache: HIT # 命中
X-Cache: MISS # 没命中
Age: 3600 # 已缓存 3600 秒
CF-Cache-Status: HIT # Cloudflare 格式
curl -I https://cdn.example.com/app.js
# 看 X-Cache / CF-Cache-Status / Age
10. 多 CDN 缓存一致性
用两家 CDN 互备时,两家缓存策略要一致:
- 同一源站
- 同一 Cache-Control
- 刷新时两家都刷
11. 常见反模式
- HTML 配长缓存:发版用户看不到
- JS 不带 hash + CDN 缓存 1 天:发版 1 天后才生效
- 每次发版全站刷新:源站压力大 + 缓存命中率归零
- 不用 stale-if-error:源站挂用户立即 5xx
- 刷新后不预热:首批用户体验差
- 发版立即删旧 JS:还在缓存旧 HTML 的用户白屏
- 不监控回源率:CDN 形同虚设
- URL 含随机 query:缓存永远不命中
- Vary: User-Agent:等于不缓存
12. 延伸阅读
- HTTP Cache RFC 9111
- Cloudflare Cache Rules
- 阿里 CDN 缓存配置
- Fastly Surrogate-Control
- 模块 02 CDN 工作原理与调度策略
- 模块 09 HTTP 缓存体系