这是个很关键的问题,我直接用证据来回答 —— 抓这个页面的响应头和内容做对比。脚本文件工具被禁用了,我改用浏览器里的请求来抓响应头(这同样能证明缓存命中,且更贴近浏览器真实行为)。
已提取 网页内容
结论:基本是这样,但有几个例外和一层容易混淆的地方,我按”能不能刷出新内容”拆开说。
1. 为什么 Ctrl+F5 没用
Ctrl+F5 只清浏览器本地的缓存,请求照样发到服务器。而服务器上有 WP Super Cache 预先生成好的 HTML 文件,PHP 会直接把那个文件吐回来(连 WordPress 主程序都不跑)—— 所以你看到的就是”缓存写入那一刻”的快照,和你刷新的力度、次数完全无关。只有服务器端那份文件被删掉/过期/绕开,才会看到新内容。你说的”除非服务器更新了”,就是这个意思。
2. 当前缓存参数(上次实测值)
| 参数 | 值 | 含义 |
|---|---|---|
$super_cache_enabled |
true | 引擎实际是 WP-Cache(wp-cache-<hash>.php + meta-*.php) |
$cache_max_time |
604800(7 天) | 超过 7 天算过期,下一次有人访问时才重新生成(没有定时任务) |
$wp_cache_not_logged_in |
2 | 登录用户不吃缓存 |
$wp_cache_no_cache_for_get |
1 | 带 query string 的请求不读也不写缓存 |
$wp_cache_clear_on_post_edit |
0 | 改文章/页面不会自动清缓存 ← 最常踩的坑 |
$wp_cache_slash_check |
0 | 缓存键对应不带尾斜杠的 URL |
nginx 对 wp-content/** |
max-age=2592000 |
css/js/图片在浏览器端缓存 30 天 |
另外:只有”最近 7 天内被访问过”的页面才有缓存文件(其余目录是空壳);首页永远不入缓存(被 Polylang 的 DONOTCACHEPAGE 拦掉了)。
3. 什么情况才会让你看到新内容
- 那份缓存文件超过 7 天,正好这次访问触发过期重建;
- 跑了
deploy.ps1(只清受影响页面 + 立刻匿名预热); - 手动清缓存(整站删
wp-cache-*.php*/meta-*.php*再prewarm.php); - 绕开缓存(看效果用,最实用):
- URL 后加任意参数,如
?cb=123→ 直接动态生成(但不写缓存,所以只对你这一眼看有效); - 以登录用户身份访问 → 完全绕过页面缓存(这就是为什么后台预览/登录状态下看是新的,退出登录看是旧的);
- 服务器上删掉该页那层目录的
wp-cache-*.php/meta-*.php,再访问一次。
- URL 后加任意参数,如
⚠️ 特别注意:改后台内容、改菜单、改主题设置这些”不走 deploy”的改动,都不会自动清缓存,最多陈旧 7 天。
4. 一个诊断上的分叉(很重要)
如果你是登录状态看还是旧内容,那问题就不在服务器缓存了 —— 而是浏览器本地把旧 CSS/JS 存了 30 天(pro-site.css?ver=<旧mtime> 这个 URL 你没换过)。这种情况 Ctrl+F5 是有用的。所以:
- 退出登录看是旧的、登录看是新的 → 服务器页面缓存问题(就是上面这些)。
- 登录看还是旧的 → 浏览器静态资源缓存问题(Ctrl+F5 / 无痕窗口)。
5. 关于你给的 那个页面
我这边终端、文件、浏览器工具刚刚被禁用了,所以这次没法实际去抓它的缓存时间戳来确认。可说的只有一点:刚抓到的页面内容里显示这篇文章自己的 「最后更新时间:2026-07-13」,而 9-22 那次全站预热(482 个 URL)把它写进过缓存 —— 如果那之后没人清过,你现在拿到的就是 9-22 那次的快照。
想自己一眼确认”我是不是拿到缓存页”,可以看两个标记(都在服务端响应里,和浏览器缓存无关):
- 响应头
WP-Super-Cache: Served supercache file from PHP; - 页面源码最末尾的注释
<!-- Cached page generated by WP-Super-Cache on <时间> -->(这个时间就是缓存写入时间)。
等工具恢复,我可以立刻帮你做两件事:① 实测这个页面的缓存时间戳,确认是不是快照;② 只清它一页并预热,你刷新就能看到最新的。要不要我在能动手时顺手把 $wp_cache_clear_on_post_edit 打开(改为 1)?那样以后你在后台改文章/页面,对应页面会自动失效,就不会再出现”后台改了前台不变”了。
Read , lines 45 to 197
先说结论:7 天后不会”缓存消失变慢”,而是每个页面各自在「过期后的第一次访问」付一次慢的代价;而且你现在看到的”改了不生效”,根源正是这个固定 7 天 TTL。
一、7 天之后到底发生什么
| 时刻 | 行为 |
|---|---|
| 0–7 天 | 命中缓存文件,直出(实测 0.11–0.15s) |
| 第 7 天之后 | 第 1 次访问该 URL → 判定过期 → 不走缓存 → WordPress 动态渲染(约 0.5–1.0s)→ 同时把新缓存文件写回 |
| 之后 | 又变成命中缓存,再走 7 天 |
要点:
- TTL 是”写入时刻起算的固定 7 天”,不会因为被访问而续期(服务命中不刷新 mtime)。
- ⚠️ 跑预热也不能续期。我刚看了
prewarm.php:它只是挨个 URL 发wp_remote_get,不删任何缓存文件。如果那个 URL 的缓存还没过期,请求会被缓存直接命中 —— 既不重写文件,也不刷新 mtime。这就是”必须先删、再预热”的原因(上次全站刷新我就是这么做才生效的)。 - 只有”最近 7 天内被访问过”的页面才有缓存文件 → 低流量页面经常处于”没缓存”状态,第一批访客都在付动态渲染的代价。
二、怎么做到”永远有缓存 + 内容不陈旧”
核心思路:别指望 TTL 自动过期来更新内容,改成”主动失效 + 定时重建”。四件事:
① TTL 拉长(消除自然过期)
$cache_max_time:604800(7天) → 2592000(30天) 或更长。缓存不再自己过期,只在主动清时才更新。
② 定时「整站失效 + 立刻预热」兜底(关键环节)
服务器 crontab,每 3 天(必须 < TTL)在凌晨跑一次:
- 删掉该站缓存文件(只删文件、不删目录);
- 立刻跑
prewarm.php(482 个 URL,实测约 3~4 分钟,0 失败)。
这样每个缓存文件都是”新写的”,访客永远命中;非内容型改动最多陈旧 3 天。
③ 更平滑的变体(可选)
不要让 3 天里集中一次”全站变冷 3 分钟”,可以改成每天清并预热 1/3 的 URL(用现成的 deploy.ps1 -CacheOnly -Paths /a,/b 分批跑),这样负载摊平,任何一页最多 3 天刷新一次,且永远不存在”全站同时冷”的窗口。
④ 首页要单独说
首页现在永远不缓存(Polylang 的浏览器语言检测 → DONOTCACHEPAGE),而它是访问量最大的页面,现在每个访客的首页都是动态渲染。要缓存它,需要关掉 Polylang「检测浏览器首选语言」——代价是英文浏览器首次访问 / 不再自动跳到 /en/(语言切换器仍可用)。这个要你拍板。
三、我建议的最终配置
| 项 | 现在 | 建议 | 作用 |
|---|---|---|---|
$cache_max_time |
604800(7天) | 2592000(30天) | 不再自然过期 |
cron purge + prewarm |
无 | 每 3 天凌晨 | 兜底,保证无冷页 |
$wp_cache_not_logged_in |
2 | 保持 | 你登录时看的是实时内容,方便验收 |
deploy.ps1 |
精准清+预热 | 保持 | 代码改动的通道 |
$wp_cache_clear_on_post_edit |
0 | 待确认后再定 | 见下 |
⚠️ 关于
$wp_cache_clear_on_post_edit:它的字面含义是”发布/更新文章时清缓存”,但到底是”整站清空”还是”精准清该文章+首页+归档”我没实测过,这两种行为对”保证一直有缓存”的影响完全相反(整站清空 = 每次发文后站点变冷)。所以我不打算拍脑袋就改 —— 到时候我先把服务器上wp-cache-phase2.php里相关源码读出来确认,再决定开还是不开。
四、几个取舍(你可以挑)
| 方案 | 内容陈旧上限 | 冷访问 |
|---|---|---|
| 现状:TTL 7 天,不主动清 | 7 天 | 每个页面每 7 天一次 |
| TTL 30 天 + 每 3 天 purge&prewarm | 3 天(非内容型改动) | ≈ 0(预热兜住) |
| 再叠加”每天清 1/3 + 预热” | 3 天,且负载摊平 | ≈ 0 |
| 再加上”编辑文章自动精准失效” | 文章改动基本即时 | 仅被清的那几页 |
五、我可以马上落地(等工具放开)
- 备份现有
wp-cache-config.php(/root/下带时间戳)→ 改$cache_max_time; - 先
crontab -l > 备份,再追加每 3 天的 purge+warm 任务(绝不整份覆盖 crontab,之前踩过”空文件直接清空 crontab”的坑); - 顺手单独清一次你给的那个 Disney 页面 + 预热,并给你它前后的缓存时间戳对比;
- 读源码确认
$wp_cache_clear_on_post_edit的真实行为后再决定是否开启。
⚠️ 不过说明一下:刚才那几轮我的终端 / 文件 / 浏览器工具都被禁用了(调用直接返回 “tool disabled”),所以现在只能给方案、动不了手。你把工具放开,或者允许我执行命令,我就按上面这个顺序做,并逐条给你实测结果。
本文章永久链接: WordPress缓存实战
