前一篇文章《从 EdgeOne 524 到 Query String 归一化》中,我记录了 WordPress 中文站在 EdgeOne 下出现 524 故障之后,对 Query String 缓存策略进行排查、调整和验证的过程。(水晶湾网址)
当时已经测试了多种文章页、列表页和归档分页,但还留下了一个没有真正覆盖到的场景:
/YYYY/MM/DD/page/N/
也就是日期归档分页。
原因很简单:测试时没有找到一个真实存在、已经产生分页的日期归档,所以只能暂时跳过。
到了 2026 年 8 月 15 日,站点当天发布的文章数量已经足够多,终于产生了真实可访问的第 3 页:
中文站:
https://www.shuijingwanwq.com/2026/08/15/page/3/
英文站:
https://en.shuijingwanwq.com/2026/08/15/page/3/
于是我决定把这个遗漏的测试项补上。
原本以为这只是一次很简单的补测,结果英文站 Cloudflare 又出现了一个有意思的现象:
Cloudflare 明明一直命中缓存,但每次返回的完整 HTML SHA-256 却不一样。
继续对比页面之后,最终发现缓存本身没有问题,真正造成哈希变化的是 Cloudflare 对页面中邮箱地址进行的动态混淆。
这次补测因此除了补齐日期归档分页,也顺便修正了一个以后进行 CDN 缓存测试时很重要的判断方法。
日期归档第 3 页终于出现
这次能够实际测试的中文页面是:
https://www.shuijingwanwq.com/2026/08/15/page/3/
浏览器中已经可以看到:
首页 / 2026 / 8月 / 15 / 第3页
页面标题则是:
日期: 2026年8月15日
下面继续列出当天较早发布的文章。

/YYYY/MM/DD/page/N/ 类型的真实页面已经出现】这正是上一篇测试中缺少的 URL 类型。
之前虽然已经验证过其他归档页和分页,但从 CDN 缓存规则的角度看:
/2026/08/15/
与:
/2026/08/15/page/3/
毕竟是两个不同的路径。
既然现在已经有真实页面,就没有必要继续依赖推测,可以直接进行实际请求验证。
中文站 EdgeOne:随机 Query String 直接命中已有缓存
中文站仍然沿用之前的测试思路。
首先请求不带参数的正常页面:
https://www.shuijingwanwq.com/2026/08/15/page/3/
然后生成一个带当前时间戳、此前没有访问过的随机 Query String:
?swq_qs_test=date-page-1786844745
形成:
https://www.shuijingwanwq.com/2026/08/15/page/3/?swq_qs_test=date-page-1786844745
测试结果很直接:
========== EdgeOne 日期归档分页 ==========
HTTP/2 200
eo-cache-status: MISS
--- RANDOM QUERY STRING ---
HTTP/2 200
eo-cache-status: HIT
正常 URL 第一次请求为:
MISS
而紧接着请求刚刚生成的随机 Query String,却直接得到:
HIT
进一步比较两份 HTML:
b032f39e333db0afe4952b22effcf9955ed1bd4a09076c6fa6a792bf9dc40a39 clean
b032f39e333db0afe4952b22effcf9955ed1bd4a09076c6fa6a792bf9dc40a39 dirty
最终:
same_body=yes

这个结果已经足以说明:
EdgeOne 没有因为这个无关 Query String 创建新的页面缓存,日期归档分页同样能够按照当前规则进行 Query String 归一化。
因此中文站这一项可以直接判定通过。
英文站 Cloudflare:随机参数同样第一次就是 HIT
然后测试英文站:
https://en.shuijingwanwq.com/2026/08/15/page/3/
同样先访问正常页面,再生成一个新的随机参数:
?swq_cf_qs_test=date-page-1786844818
第一次测试时得到:
CLEAN:
cf-cache-status: HIT
age: 254
随后请求刚刚生成的随机 Query String:
DIRTY:
cf-cache-status: HIT
age: 255
这个现象本身已经很有价值。
因为这个随机参数刚刚才生成,此前并不存在对应的访问历史。
如果 Cloudflare 把完整 Query String 当成独立缓存键,那么第一次访问这个随机 URL,通常应该更容易看到新的缓存对象。
但实际结果却是:
HIT
而且缓存年龄直接从:
254
增长到了:
255
从这一点来看,随机 Query String 很明显正在继续使用已有缓存。
但完整 HTML SHA-256 居然不同
问题出现在正文比较上。
第一次测试得到:
a82d0be563742050ebb8e0595c6182a9a657d0f3d9da831da0081e9d74f1b7b5 clean
e595a892523e343bf52f093cdcc98951e1cc1cb9b770d64c2b4bbe18cba602f8 dirty
same_body=no
也就是说:
Clean SHA-256 != Dirty SHA-256
如果按照之前比较直接的判断方式,很容易得到:
随机 Query String
→ 页面正文发生变化
→ 可能没有真正实现缓存归一化
但这个结论和缓存头又明显存在矛盾。
因为随机参数第一次访问已经是:
HIT
而且:
age
仍然沿着原来的缓存年龄增长。
所以这里不能直接根据整页 SHA-256 下结论。
先检查相同 URL 自己是否稳定
为了排除 Query String 本身的影响,我又做了一组对照测试:
Clean 1
Clean 2
Dirty 1
Dirty 2
也就是:
- 相同 Clean URL 连续访问两次;
- 相同 Dirty URL 连续访问两次。
缓存结果如下:
age: 341
cf-cache-status: HIT
age: 342
cf-cache-status: HIT
age: 344
cf-cache-status: HIT
age: 345
cf-cache-status: HIT
四次请求全部:
HIT
缓存年龄也持续增长:
341
342
344
345
没有出现 Dirty 请求重新建立缓存的迹象。
但下面的原始 SHA-256 却全部不同。

这一步实际上已经说明:
问题不可能简单归因于 Query String。
因为就连:
Clean 1
和:
Clean 2
这两个完全相同的 URL,返回的 HTML SHA-256 也不同。
比较结果是:
clean1_vs_clean2=different
dirty1_vs_dirty2=different
clean_vs_dirty=different
这意味着 Cloudflare 返回 HTML 的过程中,还有某个动态内容在发生变化。
直接比较 HTML,终于找到唯一差异
继续对:
Clean 1
和:
Clean 2
进行逐行比较以后,终于找到了真正的变化。
第一次响应中,页面底部 Mail 社交链接的一部分是:
href="/cdn-cgi/l/email-protection#0e7d667b6764676069796f60797f4e69636f6762206d6163"
第二次则变成:
href="/cdn-cgi/l/email-protection#1a69726f737073747d6d7b746d6b5a7d777b737634797577"
其他页面内容并没有发生变化。
差异集中在:
/cdn-cgi/l/email-protection#...
这里。
到这一步,问题就比较清楚了。
页面底部存在邮件链接,而经过 Cloudflare 返回以后,邮箱地址被改写成了:
/cdn-cgi/l/email-protection#...
形式。
这个保护值会变化,因此即使:
- WordPress 页面内容没有变化;
- 文章列表没有变化;
- 分页没有变化;
- Cloudflare 命中的还是已有缓存;
最终发送到客户端的 HTML 仍然可能出现几个字节的不同。
而 SHA-256 对任何一个字节变化都会敏感。
所以此前:
same_body=no
并不能说明 Cloudflare 缓存出现了问题。
将 Cloudflare 动态邮箱保护值归一化
为了最终确认,我又做了一次处理。
在计算 SHA-256 之前,只把:
/cdn-cgi/l/email-protection#后面的动态值
统一替换为:
/cdn-cgi/l/email-protection#NORMALIZED
其他 HTML 一个字节也不动。
然后重新计算:
Clean 1
Clean 2
Dirty 1
Dirty 2
四份页面的 SHA-256。
最终结果:
clean1 7eb9c5d221cde81de8a9824f433e5fff360d70940ee01afeed97e7899ef854bf
clean2 7eb9c5d221cde81de8a9824f433e5fff360d70940ee01afeed97e7899ef854bf
dirty1 7eb9c5d221cde81de8a9824f433e5fff360d70940ee01afeed97e7899ef854bf
dirty2 7eb9c5d221cde81de8a9824f433e5fff360d70940ee01afeed97e7899ef854bf
四份完全一致。
最终比较:
clean1_vs_clean2 = same
dirty1_vs_dirty2 = same
clean_vs_dirty = same

到这里,整个问题就完全闭环了。
英文站 Cloudflare 同样通过
综合全部证据,英文站的日期归档分页最终同样可以判定通过。
测试 URL:
https://en.shuijingwanwq.com/2026/08/15/page/3/
随机 Query String 第一次访问:
cf-cache-status: HIT
缓存年龄连续增长:
341
342
344
345
说明随机 Query String 没有明显创建新的独立缓存对象。
最初出现的:
Clean SHA-256 != Dirty SHA-256
进一步证明不是 Query String 引起。
因为完全相同的:
Clean 1
Clean 2
原始 HTML 同样不同。
最后将:
/cdn-cgi/l/email-protection#...
这个 Cloudflare 动态字段归一化以后:
Clean 1 = Clean 2 = Dirty 1 = Dirty 2
因此最终结论是:
Cloudflare 对日期归档分页的 Query String 归一化同样正常。
两个 CDN 的最终测试结果
这次补测可以简单整理为下面两组结果。
中文站 EdgeOne:
URL:
/2026/08/15/page/3/
HTTP:
200
Clean:
MISS
随机 Query String:
HIT
原始 HTML:
SHA-256 一致
same_body:
yes
结果:
通过
英文站 Cloudflare:
URL:
/2026/08/15/page/3/
HTTP:
200
Clean:
HIT
随机 Query String 首次访问:
HIT
缓存 age:
连续增长
原始 HTML:
存在动态差异
差异来源:
/cdn-cgi/l/email-protection#...
归一化 Cloudflare 动态字段后:
Clean 1 = Clean 2 = Dirty 1 = Dirty 2
结果:
通过
至此,上一篇文章中没有覆盖到的:
/YYYY/MM/DD/page/N/
日期归档分页已经正式补测完成。
这次真正值得记录的是测试方法的变化
最开始,我只是想补一个漏掉的日期归档分页。
但这次最有价值的收获,反而不是日期分页本身,而是进一步确认:
完整 HTML 的原始 SHA-256,不能在所有 CDN 场景中被当成页面缓存一致性的绝对判据。
中文站 EdgeOne 这次非常简单:
Clean SHA-256 = Dirty SHA-256
因此可以直接判断内容一致。
但是英文站经过 Cloudflare 以后,情况不同。
Cloudflare还可能在缓存对象返回给浏览器的过程中,对某些 HTML 内容进行动态处理。
这次已经实际遇到:
/cdn-cgi/l/email-protection#...
每次发生变化。
这种差异并不代表:
- WordPress 生成了不同页面;
- Query String 导致了不同页面;
- Cloudflare 建立了不同缓存;
- 缓存规则失效。
它只是说明:
客户端最终拿到的 HTML,还可能包含 CDN 自己产生的动态字段。
以后如何测试 Query String 缓存
经过这次验证,以后再测试类似问题,我会把判断顺序调整一下。
首先检查:
HTTP 状态
确认页面本身能够正常访问。
然后检查 CDN 的缓存状态,例如:
eo-cache-status
或者:
cf-cache-status
接着观察随机 Query String 第一次请求究竟是:
MISS
还是:
HIT
对于 Cloudflare,还可以继续结合:
age
判断它是不是沿用已有缓存对象。
如果还需要进行正文级别确认,再比较 HTML。
但如果原始 SHA-256 不一致,不再立即判定:
缓存失败
而是先检查:
相同 Clean URL 连续请求是否也不同
如果相同 URL 自己都不稳定,那么就继续定位动态字段。
最后,把明确属于 CDN 自身响应处理、与业务页面内容无关的动态字段归一化以后,再进行真正的正文哈希比较。
相比单纯使用:
same_body=yes/no
这种方法明显更加可靠。
总结
上一篇《从 EdgeOne 524 到 Query String 归一化》留下的日期归档分页测试缺口,这次终于补上了。
真实测试页面为:
/2026/08/15/page/3/
中文站 EdgeOne 中:
Clean:MISS
Dirty:HIT
same_body=yes
日期归档分页 Query String 归一化工作正常。
英文站 Cloudflare 中,随机 Query String 第一次访问同样直接:
HIT
缓存年龄持续增长。
虽然原始 HTML SHA-256 一度全部不同,但最终通过逐行比较确认,唯一差异来自:
/cdn-cgi/l/email-protection#...
将这一 Cloudflare 动态字段归一化以后:
Clean 1
Clean 2
Dirty 1
Dirty 2
四份 HTML 的 SHA-256 完全一致。
因此最终可以确认:
EdgeOne 与 Cloudflare 对 WordPress 日期归档分页的 Query String 归一化均工作正常。
而这次测试也进一步完善了后续 CDN 验证的方法:
先看缓存状态和缓存年龄,再判断随机参数是否命中已有缓存;需要比较正文时,还要先排除 CDN 自己的动态响应改写,不能仅凭整页原始 SHA-256 不同就判断缓存异常。
Linux 服务器运维、部署与线上故障排查
如果你的网站或后端服务部署在 Linux 服务器上,遇到访问异常、Nginx 配置问题、MySQL / Redis 异常、Docker 服务不可用、磁盘占满、CPU / 内存过高等问题,可以联系我做一次远程排查。
适合以下场景:
✅ 网站打不开或访问不稳定
✅ Nginx / PHP-FPM 配置异常
✅ MySQL / Redis 性能或连接问题
✅ Docker 服务部署与维护
✅ 服务器迁移与环境配置
✅ CPU / 内存 / 磁盘异常排查
服务内容:
✅ Linux 环境检查
✅ 网站部署与迁移
✅ Nginx / PHP-FPM / MySQL / Redis 排查
✅ Docker 配置与维护
✅ 服务器性能分析
✅ 长期远程运维支持
如需咨询,请联系我,并注明:Linux 运维咨询。
联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com

发表回复