发布时间:2026-09-24 05:00 更新时间:2026-09-24 05:00 阅读量:0
改版上线后,自己刷新是新的,客户打开还是老页面;或者手机上看到的和电脑上看到的不是同一版。这类问题十有八九出在 CDN 缓存上,而真正让人绕晕的不是“缓存没刷新”,而是缓存键把不同的 URL 归并成了一块,或者源站响应头和 CDN 规则互相打架,导致你以为刷了、其实没刷到点上。下面按“缓存键怎么构成 → 为什么改版后还是旧内容 → purge 怎么用 → 源站头与 CDN 规则谁说了算”的顺序拆开讲。
CDN 边缘节点不是按“一个文件一份缓存”来存的,而是按缓存键(Cache Key)做索引。同一个缓存键的请求,直接命中同一份副本。缓存键通常由这些要素拼成:完整 URL 的 host 与 path、查询字符串(query string)、部分请求头(如 Accept-Encoding 区分 gzip/br)、有时还包括协议(http 与 https 分开)。
几个常见坑:一是查询字符串。如果 CDN 规则配成“忽略全部查询参数”,那么 /index.php?ver=2 和 /index.php?ver=3 会被当成同一个键,你带参数强制拉新页面根本没用。二是协议与 host,带 www 和不带 www 一般算两套缓存,只刷一个另一个照旧。三是 Vary 类响应头,源站如果对 User-Agent 或 Cookie 做 Vary,缓存键维度会变多,命中率下降,也更容易出现“有的人新、有的人旧”。
排查第一步是确认当前请求到底命中没命中。多数 CDN 会在响应头里带缓存状态字段,名称各家不同,常见的有 X-Cache、X-Cache-Status、CF-Cache-Status 之类,具体以你所用 CDN 的官方文档为准。用 curl 看响应头是最快的方式:
curl -I -s https://www.example.com/ | grep -iE 'x-cache|cache-status|age|last-modified|etag|vary'
带上查询参数对比,观察是否命中同一份缓存
curl -I -s 'https://www.example.com/?v=20260901' | grep -iE 'x-cache|age'
重点看 Age:这个值表示该副本在边缘已经存活了多少秒。如果源站刚改完,Age 却是几千秒,说明命中的是旧副本;如果 Age 是 0 或很小,说明这次是回源拉的,内容应当是新版。
按概率从高到低排,通常是这几种。
改的是源站文件,但 URL 没变。 首页、列表页这类动态又带缓存的页面,URL 一直是同一个,CDN 自然继续返回旧副本,直到 TTL 到期或被手动刷新。静态资源同理,/style.css 文件名没换,节点上的副本就还是老的。
只刷了目录或首页,没刷到实际命中的对象。 很多 CDN 支持按 URL、按目录、按通配符刷新,但通配符各平台语法和限制不同,有的不支持跨目录通配。刷错范围,等于没刷。
多层缓存叠加。 浏览器本地缓存、CDN 边缘缓存、源站反向代理缓存(Nginx proxy_cache)三层里任意一层没更新,用户看到的就可能是旧的。你用无痕窗口看是新的,只能证明浏览器这层过了,证明不了边缘层。
缓存键被忽略参数影响。 前面提到,若配置忽略 query string,你加的版本参数不会生成新键,反而可能把不同内容错误合并,出现串页。
回源拿到的是旧内容。 源站本身有 Nginx 反向代理缓存或对象存储,CDN 回源时拿到的就是旧的,边缘刷新再多次也是徒劳。这种情况要先在源站服务器上直接 curl 本地,确认源站返回的是新版。
刷新分两种:purge(清除副本,下次访问回源拉新)和预热(主动把新内容推到边缘)。改版后一般先 purge,再视情况预热。操作上有几个原则:
先定位“实际命中的 URL”,再刷它,不要只刷首页。首页里引用的 CSS、JS、图片都是独立缓存对象,最好在改版时给静态资源加版本号或哈希文件名,这样新文件名天然是新键,不用逐个刷。这是比反复 purge 更稳的做法。
刷新时优先按完整 URL(含协议与 host)刷,涉及整站改版再考虑目录级或全站刷新。全站刷新会带来回源洪峰,源站扛不住时会出现短暂 502,建议错峰或分批。刷新后立刻用 curl 看 Age 是否归零、内容是否更新,别凭感觉。
关于源站响应头与 CDN 规则的优先级:大多数 CDN 的默认逻辑是源站响应头优先,CDN 控制台的缓存规则在其基础上做覆盖或补充,但“谁覆盖谁”取决于平台配置项,有的平台允许在控制台强制指定 TTL 并忽略源站头,有的则完全尊重源站。关键是要统一,别一边源站给 Cache-Control: no-cache,一边控制台设了 7 天 TTL,两边打架时以平台实际生效结果为准,必须实测确认。典型的源站头写法:
# HTML 页面:允许缓存但要求回源校验,适合改版频繁的站点
location ~* \.(html)$ {
add_header Cache-Control "public, max-age=0, must-revalidate";
}
带哈希的静态资源:可以放心长缓存
location ~* \.(css|js|png|jpg|webp|woff2)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000, immutable";
}
注意 add_header 只在特定响应码下生效,且多个 location 嵌套时可能被覆盖,改完务必用 curl 在源站本机验证头是否真的输出。若源站前面还有一层 Nginx 反向代理缓存,还要确认 proxy_cache 的 key 与过期时间,否则 CDN 回源拿到的仍是旧副本。
遇到“CDN 缓存住旧页面”,按这个顺序走:先用 curl 看响应头确认命中状态与 Age;再核对缓存键是否被 query string、协议、host 或 Vary 影响;然后确认源站本机返回的已是新版;最后才做 purge,并优先用“静态资源加哈希文件名”的方式从根上减少刷新依赖。源站头与 CDN 规则务必保持一套口径,改完实测响应头,不要只信控制台界面上的勾选。各家 CDN 的缓存键配置项、刷新配额与通配语法差异较大,具体以对应平台的官方文档和实际环境测试结果为准。
| 📑 | 📅 |
|---|---|
| Nginx 一张证书配多个域名:SAN 填写与漏配排查 | 2026-09-24 |
| 网站切HTTPS后百度统计没数据:referrer、混合内容与代码位置排查 | 2026-09-23 |
| 宝塔面板SSL证书手动替换:证书链、私钥校验与reload排查 | 2026-09-23 |
| WordPress后台自动更新失败:权限、FTP常量与目录属主逐项定位 | 2026-09-23 |
| 宝塔新建站点403 Forbidden:权限位、属主与open_basedir三重排查 | 2026-09-23 |
| 宝塔面板磁盘挂载与网站目录迁移:/www 换盘后的路径、权限与面板数据同步 | 2026-09-24 |
| WordPress改文章前台不变:三层缓存清理顺序与验证 | 2026-09-24 |
| WordPress数据库连不上但宝塔显示正常:主机名与socket排查 | 2026-09-24 |
| 宝塔面板Nginx伪静态改了不生效:规则文件位置与重载验证 | 2026-09-24 |
| WordPress 开启 HTTPS 后台重定向循环:is_ssl 与反代头排查 | 2026-09-24 |