CDN 缓存刷新怎么做:发布新版本后用户仍看到旧页面的处理办法

网站刚发布新版本,自己这边看一切正常,用户和同事却反馈还在看旧页面——这是上线后最常见的缓存问题。这篇文章会帮助你解决它:先教你判断旧页面被缓存在哪一层,再给出 CDN 缓存刷新的具体操作、静态资源的版本化处理,以及一套发布后验证缓存是否生效的命令。按顺序做完,新版本就能稳定地被所有访客看到。

CDN 缓存刷新封面配图

先判断旧页面被缓存在哪一层

刷新之前要先弄清楚”谁在缓存”,否则刷新了 CDN 却发现是浏览器在缓存,等于白忙一场。一次页面请求从访客到源站,可能经过三层缓存,每一层的处理方式不同:

  1. 浏览器本地缓存:访客自己的电脑保存了页面副本,由响应头里的 Cache-Control 控制,只有访客强制刷新(Ctrl+F5)或头信息过期才会更新;
  2. CDN(内容分发网络,把页面和静态资源分发到离访客更近的服务器)边缘节点缓存:在各地区节点保存页面副本,需要通过刷新(Purge)操作清除;
  3. 源站自身缓存:WordPress 缓存插件、页面缓存或对象缓存生成的静态副本,要在插件里清理。

判断方法很直接:先用浏览器无痕窗口打开页面。无痕窗口不受浏览器本地缓存影响,如果无痕窗口看到的还是旧页面,说明缓存不在浏览器,而在 CDN 或源站。接着在服务器上直接请求源站本身(绕过 CDN):

curl -s --max-time 10 -H "Host: 你的域名" http://源站内网IP/页面路径/ | grep -o "版本标识文字"

把”版本标识文字”换成新版本里才有的内容(比如新版的导航文案)。能匹配到,说明源站已是新版,问题在 CDN 缓存层,执行下一节的刷新即可;匹配不到,说明源站自身缓存还没清,先去缓存插件里点”清除缓存”,再回头检查 CDN。

CDN 缓存刷新的具体操作

确认问题在 CDN 层后,就可以执行刷新了。各家的控制台入口名称略有差异(”缓存刷新””Purge Cache””清除缓存”都指同一件事),但刷新类型基本只有两种,选错类型是刷新后旧页面依旧的常见原因:

  • URL 刷新(精准刷新):只清除你填写的具体地址。适合只改了几篇文章或几个页面的场景,生效最快,通常 1-5 分钟内全球节点更新完毕;
  • 目录刷新:清除某个路径下所有缓存,比如整站 https://你的域名/ 。适合大规模改版,但会瞬间打高源站压力——所有节点同时回源拉新内容,配额也不够用(多数服务商每天限制几十到几百条)。

实际操作建议按”先小后大”来:先刷新出问题的具体页面 URL,注意把带参数和不带参数的变体都填上(/page/ 和 /page/index.html 若都曾被访问过,都要刷)。等 5 分钟后验证,如果个别页面仍是旧版,再把范围扩大到目录刷新。

有一个高频误区要提醒:只刷新 HTML 页面、不处理 CSS 和 JS 文件,是”刷新了还是旧页面”的第二大原因。页面 HTML 已经是新版,但它引用的样式和脚本文件名没变,CDN 上还是旧文件,页面看起来就”没变”。这就要靠下一节的版本化方案来根治。刷新操作与缓存头的配合原理,在网站优化一文中有更完整的加载链路分析。

CDN 缓存刷新流程示意图

静态资源版本化:让旧缓存自然失效

对 CSS、JS、图片这类静态资源,比每次手工刷新更好的办法,是在文件名里加版本号,让每一次发版都产生全新的 URL。新 URL 在 CDN 上没有历史缓存,节点会直接回源拉取最新文件,从根本上绕开”旧文件赖着不走”的问题:

<link rel="stylesheet" href="/assets/style.css?v=20261101">
<script src="/assets/app.js?v=20261101"></script>

也可以改成把版本号放进文件名本身(style.20261101.css),效果相同。WordPress 站点用 wp_enqueue_style() 和 wp_enqueue_script() 注册资源时,第四个参数传版本号即可自动附加 ?v= 查询串。前端工程化项目(Webpack、Vite)默认会在构建时给文件名加内容哈希,天然支持这套机制,无需额外配置。

配套的关键是响应头。静态资源文件名带版本后,就可以放心把 Cache-Control 设长,让 CDN 和浏览器长期缓存;HTML 页面本身则要保持短缓存或不缓存,保证每次都能尽快拿到引用新资源的页面。一个经过验证的组合是:

# HTML 页面:短缓存
location ~* \.html$ {
    add_header Cache-Control "max-age=300, must-revalidate";
}
# 带版本号的静态资源:长缓存
location ~* \.(css|js|png|jpg|webp|woff2)$ {
    add_header Cache-Control "max-age=31536000, immutable";
}

这样配置之后,日常发版基本不再需要手动刷新 CDN:HTML 在 5 分钟内自然过期,新 HTML 引用的又是全新文件名的静态资源。只在紧急回滚或修正严重错误时,才需要回到上一节的手工刷新。

这个思路同样适用于托管环境。Hostease 的虚拟主机支持自定义 .htaccess 缓存规则,搭配 CDN 的”开发模式”(临时绕过缓存直连源站)可以在调试阶段快速验证新版效果。

静态资源版本化架构示意图

发布后的缓存验证命令

刷新和版本化做完,最后一步是验证,不要只靠肉眼对比页面。下面三条命令覆盖了 HTML、响应头和全球节点三个角度:

# 1. 确认边缘节点返回的 HTML 已是新版(看版本标识文字是否存在)
curl -s --max-time 10 https://你的域名/页面路径/ | grep -o "版本标识文字"

# 2. 检查响应头里的缓存命中情况与剩余有效期
curl -sI --max-time 10 https://你的域名/页面路径/ | grep -iE "cache-control|age|x-cache|cf-cache-status"

# 3. 静态资源是否已带新版本号
curl -sI --max-time 10 "https://你的域名/assets/style.css?v=20261101" | grep -iE "HTTP|cache-control|age"

第二条命令的解读要点:x-cache: HIT 或 cf-cache-status: HIT 表示内容来自 CDN 缓存节点;age 字段表示当前副本已经缓存了多少秒,如果刷新后 age 仍在持续增长且内容是旧的,说明这次刷新没有覆盖到该节点,需要重新提交刷新或检查 URL 是否填写正确。

验证时机也有讲究:提交刷新后先等 5 分钟再查,刷新任务本身有排队时间;如果使用了多家 CDN 或多地区节点,可以用在线的多地点测速工具从不同地区抽查,避免”本地节点已更新、海外节点还是旧版”的盲区。

缓存验证对比示意图

建立发布前后的缓存检查习惯

处理完一次旧页面问题后,更值得做的是把缓存管理纳入日常发版流程,让问题不再依赖事后救火。实践中被验证有效的做法有四条:

  1. 发版清单里加一行”缓存动作”:改了哪些页面、需要刷新哪些 URL、静态资源版本号是否已更新,逐项打勾后再通知上线;
  2. 每次发版固定带版本号发布静态资源,把手工刷新留给 HTML 页面,缩小刷新范围;
  3. 记录每次刷新的提交时间和生效时间,积累自己的基线数据——不同服务商的生效速度差异很大,掌握实际数值后预估更准确;
  4. 上线后 10 分钟做一次远程抽查(用上面的 curl 命令或无痕窗口),确认新版对公网访客可见后再关闭发布窗口。

缓存规则和页面结构的对应关系,可以结合 WordPress 分类里的插件缓存教程一起看;如果问题根源出在服务器配置层,比如 Nginx 缓存策略或 PHP 会话处理,服务器分类里有更底层的排查文章。

总结一下完整路径:先用无痕窗口和源站直连请求定位缓存层,再按”URL 刷新优先、目录刷新兜底”的顺序执行 CDN 缓存刷新,同时用静态资源版本化让旧缓存自然失效,最后用 curl 验证边缘节点确实返回新版。日常发版遵循”HTML 短缓存、静态资源长缓存加版本号”的组合,绝大多数旧页面问题都能在上线后几分钟内自行消解。

如果你在配置过程中发现主机环境限制较多——比如无法自定义缓存头、源站缓存插件反复失效——可以考虑更换到可控性更强的环境。Hostease 的虚拟主机提供缓存规则自定义能力和中文技术支持,遇到复杂的缓存问题时可以直接提交工单协助排查,配合本文的验证命令,多数缓存问题都能在一小时内闭环。

发表评论