你打开CDN控制台,面对一堆“缓存过期时间”、“忽略参数”、“优先级”的输入框,是不是总有一种“填个默认值拉倒”的冲动?别急,我见过太多因为缓存规则没配好,导致线上事故翻车的故事——图片缓存一天,用户换了头像死活刷不出来;API接口缓存五分钟,活动数据一直在展示昨天的价格;更惨的是,全站强制缓存,结果后端升级了前端资源,用户浏览器里还是老代码,页面直接白屏,缓存规则配置看着简单,里面的弯弯绕绕,足够让一个架构师失眠三个晚上。
今天咱们不扯玄乎的术语,直接上干货,我把缓存规则配置拆成三个核心决策点:缓存什么、缓存多久、谁来覆盖谁的缓存,搞明白这三件事,你也能配出产线级稳定的缓存策略。
缓存什么?——粒度与命中率的博弈
CDN缓存的对象是HTTP响应,但同一个域名下,不同资源的时效性天差地别,按粒度划分,主流的配置方式有三种:
基于路径前缀(Path Prefix)
/*.jpg 或 /static/*,这是最直观的做法,适合资源类型单一、目录结构清晰的站点,优点是配置简单,一眼能看懂;缺点是粒度太粗,万一某个子目录下的图片需要短缓存(比如用户头像),你不得不单独再加一条规则覆盖。

缓存规则配置,其实就这三招—一个老炮儿的实战笔记
基于文件扩展名(File Extension)
常见做法是 *.js、*.css、*.png 各自配不同的TTL,这在静态资源为主的前后端分离架构中非常顺手,因为扩展名天然反映了资源类型,但问题在于:如果你们用了不标准的后缀(.js?v=1 带参数),或者某些API接口用 .json 结尾但内容实时变化,扩展名就会产生误导。
基于请求头/参数(Header/Cookie/Query String)
这是高级玩法,比如根据 User-Agent 判断移动端与否分别缓存不同版本,或者根据 Cookie: language 缓存对应语言的内容,更常见的是忽略参数——URL后带 ?t=123 这种防止浏览器缓存的随机数,如果不忽略参数,CDN会为每个不同的参数值创建独立缓存,导致命中率暴跌。
方案对比(一句话总结):
- 路径前缀:简单粗暴,适合中小型站点。
- 文件扩展名:标准化程度高,适合静态资源分离的架构。
- 请求头/参数:灵活但维护成本高,适合需要精细化缓存的大流量场景。
选型建议:
如果你的资源路径和扩展名都很规范,优先用“扩展名+路径”组合。*.js 统一缓存一天,但 /api/* 路径下的所有文件强制不缓存,如果遇到动态参数,别犹豫,开启“忽略参数”模式(通常CDN平台默认开启),然后在需要区分参数的少数URL上单独写规则,记住一句话:能用路径和扩展名解决的事,就不要动用请求头,后者会让你排查问题的时候想砸键盘。
缓存多久?——TTL不是越大越好
TTL(Time To Live)是最容易被误解的参数,很多人觉得“缓存时间越长,回源越少,性能越好”,于是给所有资源设个24小时,但真实情况是:TTL设置不当,要么用户看到过期内容,要么CDN频繁回源浪费带宽。
技术上讲,CDN的缓存TTL生效是有层级的:
- 浏览器本地缓存(通常通过
Cache-Control: max-age=xxx控制) - CDN边缘节点缓存(你配置的TTL)
- CDN中间层/父层缓存(有些CDN有L1/L2架构)
- 源站缓存(如果源站有CDN或反向代理)
我们配置的TTL,本质上是在告诉CDN边缘节点:“这个资源从源站取回来后,在我规定的时间内不要再去问源站”,但注意:Cache-Control: s-maxage 和 max-age 可以同时存在,CDN优先遵循 s-maxage,如果没有则用 max-age。
两种主流策略:
- 统一长缓存 + 版本号强制刷新:给所有静态资源设置24h或更长TTL,然后通过文件名加hash(
app.a1b2c3.js)来强制CDN回源,这是目前最推荐的做法,兼顾性能与更新实时性。 - 差异化TTL:根据资源更新频率分级。
- 不频繁:logo、字体 → 30天
- 较频繁:CSS/JS(有hash)→ 7天
- 频繁:用户头像、商品图片 → 5分钟
- 实时:API、SSR页面 → 不缓存或1分钟
适用场景分析:
| 场景 | 推荐TTL策略 | 原因 |
|------|------------|------|
| 单页应用(SPA)静态资源 | 长TTL + 文件hash | 资源版本可控,几乎不回源 |管理系统 | 短TTL(5-30分钟) | 编辑频繁,需尽快同步 |
| 电商商品详情页 | 按SKU动态设置TTL | 秒杀商品需0缓存,常规商品可缓存1分钟 |
| 新闻门户 | 首页不缓存或1分钟,文章页30分钟 | 首页热点变化快,文章相对稳定 |
选型建议:
不要试图用“一个TTL打天下”,先在控制台开启“缓存分层配置”——源站返回的 Cache-Control 头部优先级高于CDN平台规则,因此你可以在后端代码里给不同接口设置不同的 max-age,CDN平台只配置一个兜底TTL(比如1小时),这样后端开发者就能灵活控制,而不需要每次找运维改CDN规则,这叫做“规则注入源头”,是真正的高级玩法。
谁来覆盖谁的缓存?——优先级与继承关系
很多CDN平台允许配置多条缓存规则,并且有优先级顺序,你可能会遇到这样的情况:配了一条 *.jpg 缓存七天,又配了一条 /user/avatar/* 缓存十分钟,结果发现头像图片还是缓存七天,原因就是规则优先级没搞清楚。
典型的问题有两个:
- 精确匹配 > 模糊匹配:大部分CDN平台遵循“更具体的规则优先”。
/user/avatar/*比*.jpg更精确,因为路径前缀匹配优先于扩展名匹配,但也有少数平台是“后添加的规则覆盖前面的”,取决于具体实现。 - 规则覆盖链:你给
*.html设置了不缓存,但源站返回了Cache-Control: max-age=3600,这时谁说了算?答案是:平台规则通常可以强制覆盖源站头部,但需要开启“忽略源站缓存头”选项,如果没开启,则遵守源站头部。
两个经典配置误区:
- 全局缓存+例外规则:很多人先配一条 全局缓存一天,然后配
/*.php不缓存,但有些CDN平台中,全局规则的优先级低于精确规则,/*.php会生效;而另一些平台恰好相反,全局规则优先级最高,导致PHP也被缓存了。 - 父层缓存与子层互斥:如果你在边缘节点缓存了,又在中间层缓存了,可能会出现“边缘节点过期后去中间层取,中间层还没过期,返回旧数据”的情况,解决方案是让中间层的TTL小于边缘层,或者干脆关闭中间层缓存。
选型建议:
配置前,先画一个“资源路径树”,然后从最窄的规则开始写。
- 先写
/api/*不缓存 - 再写
/static/*.js缓存7天 - 再写
/static/*缓存1天 - 最后写 兜底不缓存
这样优先级清晰,调试时按顺序检查即可,一定记得在CDN控制台里开启“日志查看”功能,用真实的请求URL去验证缓存是否命中,不要靠猜。
写在最后
缓存规则配置从来不是“填个值”就完事的事,它是一门权衡的艺术——你要在命中率、更新延迟、源站压力三者之间找到平衡点,我的经验是:先做减法,后做加法,所有资源默认不缓存,然后根据实际业务需求,一条一条加上缓存规则,每加一条都要问自己:“这个资源真的需要缓存吗?缓存多久合适?会不会影响用户看到最新内容?”
当你把这三招(缓存什么、缓存多久、谁覆盖谁)想透了,再去面对CDN控制台上密密麻麻的输入框,就跟看菜单一样清晰,最后送你一句老炮儿的心里话:别迷信默认配置,也别迷信自己的直觉,用真实流量和日志说话。
发表评论