缓存基础
CDN 缓存到底要解决什么问题?核心不是“把页面存起来”这么简单,而是把“离用户最近的节点”变成一个稳定的内容分发层。对大多数网站来说,真正的瓶颈不是服务器算力,而是网络往返、资源加载和缓存命中率。把静态资源按类型分层缓存,往往能比升级机器更快地改善体验。
先别把缓存当成“越久越好”
缓存策略最容易出错的地方,是把所有内容都设成长期缓存。HTML、用户个人页、促销页和接口返回值,都不适合用同一套规则。一个典型的例子是电商站:商品详情页每次价格或库存变动都可能需要及时更新,而首页的主图和样式文件可以缓存很久。
Cache-Control 响应头
# 强缓存:浏览器可直接复用,减少回源
location ~* \.(jpg|png|webp)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# 弱缓存:浏览器仍会验证资源是否变化
location ~* \.html$ {
add_header Cache-Control "public, max-age=0, must-revalidate";
}
# 不缓存:敏感页面和管理后台始终回源
location /admin/ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
如果你使用 Cloudflare、Fastly 或 Akamai 这类边缘网络,缓存规则通常不只看响应头,还会看 URL、请求方法、Cookie 和查询参数。一个看起来“无害”的 ?v=1.2 参数,可能会让 CDN 误判成新的资源,从而降低命中率。
按文件类型的推荐缓存策略
| 文件类型 | CDN 缓存 TTL | 浏览器缓存 TTL | 策略说明 |
|---|---|---|---|
| HTML | 0-1h | 0-10min | 经常更新,短缓存 |
| CSS/JS(哈希文件名) | 365d | 365d | 文件名变化即新版本 |
| CSS/JS(普通文件名) | 7d | 1d | 适中缓存,版本变化时清除 |
| 图片(JPG/PNG/WebP) | 30-365d | 30-365d | 很少变化,长缓存 |
| 字体文件 | 365d | 365d | 几乎不变 |
| API 响应(GET) | 0-5min | 0 | 动态数据,短缓存或不缓存 |
| PDF/下载文件 | 30d | 30d | 适中缓存 |
一个更稳妥的思路
- 纯静态文件:尽量长期缓存;
- 页面和接口:使用短 TTL 或按版本控制;
- 个人化内容:不要缓存,或者只对匿名请求做少量缓存。
缓存清除策略
缓存清理经常比配置更重要。部署新版本、替换图片、修复错误文案,都会触发“旧内容还在边缘节点上被连续命中的”问题。
什么时候需要清除缓存
- 部署新版本 — 更新 CSS/JS/HTML 后;
- 修复错误内容 — 更正页面中的错误信息;
- 更换图片 — 替换产品图片或设计素材;
- 紧急更新 — 发布价格变动、公告或安全补丁。
清除方法
# Cloudflare 清除缓存(API)
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"files":["https://example.com/css/style.css","https://example.com/page"]}'
# 清除全部缓存
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}'
缓存命中率优化
想提升命中率,最有效的并不是“堆更多规则”,而是让资源的 URL 设计更稳定。比较容易忽略的点是:同一资源通过多个 URL 被访问,或者请求里面带了大量跟踪参数。
# 忽略查询参数中的 utm_* 和 fbclid,减少缓存碎片
if ($args ~* "(utm_|fbclid|gclid)") {
set $args '';
}
推荐做法
- 保持一致的 URL — 避免 www 与非 www、带尾斜杠与不带尾斜杠造成缓存分裂;
- 设置合理的 TTL — 过短的 TTL 会让缓存失去意义,至少要有 1 小时以上的基础缓存;
- 按文件名版本化 —
style.a1b2c3.js比style.js更适合长期缓存; - 静态资源不附带 Cookie — 这样才能真正命中边缘缓存;
- 把动态内容与静态内容分离 — 例如图片和 CSS 放 CDN,接口则由应用层控制。
常见场景配置
场景一:WordPress 网站
缓存策略:
- /wp-content/uploads/* → 缓存 30 天
- /wp-includes/*.css,*.js → 缓存 365 天
- /wp-admin/* → 不缓存
- /*.php → 不缓存
- HTML 页面 → 缓存 1 小时
场景二:静态站点(Astro/Hugo/Next.js 导出)
缓存策略:
- /*.html → 缓存 1 小时
- /_next/static/* → 缓存 365 天
- /assets/* → 缓存 365 天
- /images/* → 缓存 30 天
- /fonts/* → 缓存 365 天
场景三:API 服务
缓存策略:
- GET /api/public/* → 缓存 5 分钟
- GET /api/prices → 缓存 1 小时
- POST/PUT/DELETE/* → 不缓存
- GET /api/user/* → 不缓存(个性化数据)
四、常见误区与排查清单
缓存策略最容易踩的坑,不是设置得太短,而是把不同内容混在同一套规则里。比如首页的品牌图标、商品页的主图、API 返回值和登录状态页面,本来就不应该使用同一条缓存规则。一个常见的现象是,网站更新了样式文件,但用户仍然看到旧页面,这通常意味着 CDN 还保留了旧版本缓存,或者边缘节点没有正确收到新的响应头。
排查时可以按下面顺序做:先看响应头是否含有正确的 Cache-Control,再确认 URL 是否稳定,最后检查是否有带有 Cookie 的个性化请求把静态资源误判成动态内容。对大多数站点来说,把静态资源和动态内容分层处理,会比盲目增加 TTL 更有效。
参考:Cloudflare Cache Rules 文档 https://developers.cloudflare.com/cache/;MDN Cache-Control 说明 https://developer.mozilla.org/docs/Web/HTTP/Headers/Cache-Control
如果你正在做网站性能优化,缓存策略往往不是“能不能加”,而是“哪些内容适合缓存,哪些内容需要实时性”。这件事做对,往往比换服务器更划算。