没有不值得去解决的问题,也没有不值得去学习的技术!

WordPress 图片迁移到 media 子域名后,EdgeOne 仍然出现大量 301 的排查与处理记录

【图3,EdgeOne 301 请求的 URL Path 排行,集中在 /wp-content/uploads/ 图片路径】

作者:

WordPress CDN 与全球加速实战

图16:浏览器访问正常,网站全球访问成功

(1) 从阿里云 DNS 到 Cloudflare 全球加速的完整迁移实战记录

这一套规则遵循 Cloudflare + WordPress 标准 CDN 架构:

(2) Cloudflare SSL/TLS 与 Cache Rules 配置实战

图12:评论实时生效

(3) WordPress + Cloudflare 推荐配置与 Cache Rules 实战优化(SSL / API / 缓存闭环完整记录)

CDN上线后的boce数据

(4) CDN 上线前后性能对比实测:WordPress 缓存误判修正与真实加速效果验证

【图9:boce 测试 cn-test,灰云直连阿里云 ECS,平均响应 0.478s】

(5) Cloudflare 免费版适合中国大陆 WordPress 主站吗?从缓存 HIT 到灰云直连阿里云 ECS 的实测复盘

【图1:腾讯云 EdgeOne 产品页,选择“立即使用”】

(6) 从 Cloudflare Free 迁移到腾讯云 EdgeOne:一次 WordPress 主站国内外加速实战

【图2:EdgeOne 上线后 boce 第二次测试,平均响应 0.354s,不可访问 2 个】

(7) Cloudflare Free 迁移到 EdgeOne 后到底快了多少?WordPress CDN 三阶段 boce 与 WebPageTest 实测对比

[图2,EdgeOne 昨日 L7 访问流量,显示 6.56 GB]

(8) EdgeOne 流量成本排查:将 WordPress uploads 静态资源迁移到 Cloudflare media 子域名

【图3,EdgeOne 301 请求的 URL Path 排行,集中在 /wp-content/uploads/ 图片路径】

(9) WordPress 图片迁移到 media 子域名后,EdgeOne 仍然出现大量 301 的排查与处理记录

最近我将 WordPress 图片资源迁移到了独立的 media 子域名:

Plaintext
https://media.shuijingwanwq.com/

原本的目标是减少主站 www.shuijingwanwq.com 的静态资源压力,并让图片资源通过单独的 CDN 链路处理。

迁移完成后,新写的文章已经能够正常使用 media.shuijingwanwq.com 的图片地址。但是在 EdgeOne 的访问分析中,我发现一个不太正常的现象:media 切换已经过去几个小时,最近 1 小时仍然有不少 301 请求。

一开始我以为是 EdgeOne 缓存、浏览器缓存,或者搜索引擎残留请求导致的。排查之后才确认:问题主要来自历史文章正文中写死的旧图片地址。

【图1,EdgeOne 最近 1 小时状态码排行中,301 仍然有 5.59 MB,占比约 2.93%】
【图1,EdgeOne 最近 1 小时状态码排行中,301 仍然有 5.59 MB,占比约 2.93%】

一、问题现象:EdgeOne 最近 1 小时仍然有 301

在 EdgeOne 指标分析中,最近 1 小时的数据大致如下:

Plaintext
200:183.2 MB,占 96.16%
301:5.59 MB,占 2.93%
404:1.55 MB,占 0.81%

单看比例,301 其实不算特别夸张。但是因为图片迁移已经完成了几个小时,理论上新页面应该尽量直接输出 media 子域名,不应该再频繁访问旧的 /wp-content/uploads/ 地址。

于是我进一步筛选状态码:

Plaintext
边缘响应状态码 = 301

筛选之后可以看到,最近 1 小时仅 301 请求就有:

Plaintext
L7 访问流量:7.25 MB
L7 访问请求数:966 次
【图2,EdgeOne 添加状态码 301 筛选后的数据】
【图2,EdgeOne 添加状态码 301 筛选后的数据】

继续查看 URL Path 排行,发现大量 301 都集中在旧图片路径上,例如:

Plaintext
/wp-content/uploads/2026/07/21-2-1024x175.png
/wp-content/uploads/2026/07/23-2-1024x180.png
/wp-content/uploads/2018/04/14-3-520x245.png
/wp-content/uploads/2023/12/3-6.png
/wp-content/uploads/2021/08/5-3.png
【图3,EdgeOne 301 请求的 URL Path 排行,集中在 /wp-content/uploads/ 图片路径】
【图3,EdgeOne 301 请求的 URL Path 排行,集中在 /wp-content/uploads/ 图片路径】

这说明,虽然图片已经迁移到 media 子域名,但是仍然有大量请求在访问旧图片 URL。

二、先确认 301 是否回源

看到 301 之后,首先要确认一个关键问题:

这些 301 是 EdgeOne 边缘直接处理,还是每次都回源到 WordPress / Nginx?

如果每次都回源,说明源站压力还在。
如果是边缘直接返回 301,问题就小很多。

我用 curl 测试其中一个旧图片地址:

Bash
curl -I https://www.shuijingwanwq.com/wp-content/uploads/2026/07/21-2-1024x175.png

返回结果中比较关键的是:

Plaintext
HTTP/2 301
location: https://media.shuijingwanwq.com/2026/07/21-2-1024x175.png
content-length: 0
server: TencentEdgeOne
x-cache-lookup: Return Directly

这个结果说明:

旧图片地址的 301 是由 EdgeOne 边缘节点直接返回的,并没有回源到 WordPress。

其中:

Plaintext
x-cache-lookup: Return Directly

是一个比较关键的信号。它说明 EdgeOne 直接返回了跳转响应,而不是把请求转发到源站后再返回。

因此,这一部分 301 虽然在 EdgeOne 统计中还存在,但它本身不是源站压力问题。

三、再确认 media 子域名图片是否正常缓存

接着测试跳转后的 media 图片地址:

Bash
curl -I https://media.shuijingwanwq.com/2026/07/21-2-1024x175.png

第一次返回:

Plaintext
HTTP/2 200
server: cloudflare
cache-control: max-age=2592000
cf-cache-status: MISS

第二次再次请求后返回:

Plaintext
HTTP/2 200
server: cloudflare
age: 10
cf-cache-status: HIT

这说明 media 子域名对应的图片资源已经可以正常被 Cloudflare 缓存。

所以当时的链路可以理解为:

Plaintext
旧图片地址:
https://www.shuijingwanwq.com/wp-content/uploads/...

EdgeOne 边缘直接 301:
location: https://media.shuijingwanwq.com/...

新图片地址:
https://media.shuijingwanwq.com/...

Cloudflare:
第一次 MISS,第二次 HIT

也就是说,图片文件本身没有反复回源,media 子域名缓存也是正常的。

四、真正的问题:旧文章 HTML 里仍然输出旧图片地址

既然 EdgeOne 301 是边缘直接处理,media 图片缓存也正常,那剩下的问题就是:

为什么还有这么多旧图片地址请求?

我先检查首页 HTML:

Bash
curl -s https://www.shuijingwanwq.com/ | grep -o "/wp-content/uploads/[^\"') ]*" | head

首页没有输出,说明首页基本是干净的。

然后检查一篇旧文章:

Bash
curl -s https://www.shuijingwanwq.com/2021/08/04/5122/ | grep -o "/wp-content/uploads/[^\"') ]*" | head

结果返回了大量旧路径:

Plaintext
/wp-content/uploads/2021/08/1-2.png
/wp-content/uploads/2021/08/1-2.png
/wp-content/uploads/2021/08/2-2.png
/wp-content/uploads/2021/08/2-2.png
/wp-content/uploads/2021/08/3-1.png

这就说明,问题不是单纯的历史缓存,而是旧文章页面本身还在输出旧图片地址。

我又在浏览器中查看这篇旧文章的页面源代码,发现确实存在大量:

Plaintext
/wp-content/uploads/
【图4,旧文章页面源代码中仍然能搜索到 /wp-content/uploads/】
【图4,旧文章页面源代码中仍然能搜索到 /wp-content/uploads/】

这就解释了为什么 EdgeOne 仍然有 301:

Plaintext
用户或爬虫访问旧文章

旧文章 HTML 中仍然包含 /wp-content/uploads/ 图片地址

浏览器继续请求旧图片地址

EdgeOne 边缘返回 301

跳转到 media.shuijingwanwq.com

五、为什么新文章正常,旧文章不正常?

一开始我还怀疑是不是经典编辑器和 Gutenberg 的差异。

后来检查后发现,跟编辑器类型没有关系。

根本原因是:

WordPress 文章正文里的图片地址,本质上是写死在 wp_posts.post_content 里的 HTML 字符串。

迁移前插入的图片,文章正文里保存的是:

HTML
<img src="https://www.shuijingwanwq.com/wp-content/uploads/2021/08/1-2.png">

迁移后新上传、新插入的图片,文章正文里保存的是:

HTML
<img src="https://media.shuijingwanwq.com/2026/07/1-22.png">

所以 media 配置只影响迁移之后新生成的图片 URL,不会自动回头修改历史文章里的 HTML。

【图5,迁移前的旧文章代码编辑器中,图片地址仍然是 www.shuijingwanwq.com/wp-content/uploads】
【图5,迁移前的旧文章代码编辑器中,图片地址仍然是 www.shuijingwanwq.com/wp-content/uploads】
【图6,迁移后的新文章代码编辑器中,图片地址已经是 media.shuijingwanwq.com】
【图6,迁移后的新文章代码编辑器中,图片地址已经是 media.shuijingwanwq.com】

六、先用 Better Search Replace 做 dry run

因为我的站点已经安装了 Better Search Replace 插件,所以没有额外安装 WP-CLI,而是直接用插件做检查。

一开始我搜索的是:

Plaintext
Search for:
/wp-content/uploads/

Replace with:
https://media.shuijingwanwq.com/

只选择:

Plaintext
wp_posts

并勾选:

Plaintext
Run as dry run

dry run 结果显示:

Plaintext
6455 cells were found that need to be updated
【图7,Better Search Replace 搜索 /wp-content/uploads/ 的 dry run 结果,显示 6455 cells】
【图7,Better Search Replace 搜索 /wp-content/uploads/ 的 dry run 结果,显示 6455 cells】

不过这个搜索条件太宽泛了,不适合直接正式替换。

因为旧文章里有两种情况:

第一种是图片完整 URL:

Plaintext
https://www.shuijingwanwq.com/wp-content/uploads/2021/08/1-2.png

这种可以安全替换成:

Plaintext
https://media.shuijingwanwq.com/2021/08/1-2.png

第二种是正文里的技术说明、路径记录、服务器目录说明,例如:

Plaintext
/wp-content/uploads/2021/07/

这种不一定是图片加载地址,可能只是文章内容的一部分。如果直接替换,反而会破坏文章原本的排查语境。

所以不能直接把所有 /wp-content/uploads/ 都替换掉。

七、改用完整旧图片域名做正式替换

更安全的搜索条件应该是完整旧图片 URL 前缀:

Plaintext
Search for:
https://www.shuijingwanwq.com/wp-content/uploads/

Replace with:
https://media.shuijingwanwq.com/

继续只选择:

Plaintext
wp_posts

并先勾选:

Plaintext
Run as dry run

这次 dry run 结果显示:

Plaintext
3304 cells were found that need to be updated
【图8,Better Search Replace 使用完整旧图片域名 dry run,匹配数量减少到 3304 cells】
【图8,Better Search Replace 使用完整旧图片域名 dry run,匹配数量减少到 3304 cells】

这个结果更符合预期。

因为它只针对历史文章中明确写死的完整旧图片地址:

Plaintext
https://www.shuijingwanwq.com/wp-content/uploads/

不会误伤普通正文里记录的相对路径:

Plaintext
/wp-content/uploads/

在正式替换前,我使用 UpdraftPlus 做了数据库备份。确认数据库备份完成后,取消 Run as dry run,执行正式替换。

正式替换结果:

Plaintext
During the search/replace, 1 tables were searched, with 3304 cells changed in 3299 updates.
【图9,Better Search Replace 正式替换成功,3304 cells changed in 3299 updates】
【图9,Better Search Replace 正式替换成功,3304 cells changed in 3299 updates】

八、清理 W3 Total Cache 后重新验证

正式替换完成后,我先查看旧文章的代码编辑器,发现图片地址已经变成:

Plaintext
https://media.shuijingwanwq.com/2021/08/1-2.png
【图10,旧文章代码编辑器中,图片地址已经从 www 替换成 media】
【图10,旧文章代码编辑器中,图片地址已经从 www 替换成 media】

但是一开始用 curl 访问前台页面时,仍然能看到旧地址。

这说明数据库已经替换成功,但前台页面缓存还没有刷新。

于是我在 WordPress 后台清理了 W3 Total Cache:

Plaintext
Performance → Purge All Caches

清理后重新执行:

Bash
curl -s "https://www.shuijingwanwq.com/2021/08/04/5122/?_nocache=$(date +%s)" | grep -o "https://www.shuijingwanwq.com/wp-content/uploads/[^\"') ]*" | head

结果没有任何输出。

再检查相对路径:

Bash
curl -s "https://www.shuijingwanwq.com/2021/08/04/5122/?_nocache=$(date +%s)" | grep -o "/wp-content/uploads/[^\"') ]*" | head

也没有任何输出。

这说明这篇旧文章前台 HTML 已经不再输出旧图片地址。

九、为什么没有继续替换剩余的 /wp-content/uploads/

第一批完整旧图片 URL 替换完成后,我又用 Better Search Replace 做了一次 dry run:

Plaintext
Search for:
/wp-content/uploads/

Replace with:
https://media.shuijingwanwq.com/

结果显示残留数量已经大幅减少。

【图11,完整 URL 替换后,再次 dry run 检查 /wp-content/uploads/ 残留】
【图11,完整 URL 替换后,再次 dry run 检查 /wp-content/uploads/ 残留】

但我没有继续正式替换这部分残留。

原因是,通过只读查询可以看到,剩余的 /wp-content/uploads/ 很多并不是图片加载 URL,而是文章正文中的技术说明、附件标题、历史修订版本,或者以前排查问题时记录的服务器路径。

例如某些文章本身就在讲:

Plaintext
通过 FlashFXP 上传文件至 /wp-content/uploads/2021/07/

这种内容如果强行替换成:

Plaintext
https://media.shuijingwanwq.com/2021/07/

反而会破坏文章原意。

所以我的处理原则是:

Plaintext
完整旧图片 URL 可以批量替换;
单独的 /wp-content/uploads/ 不再无脑替换。

十、这次排查后的结论

这次问题的核心并不是 EdgeOne 301 异常,也不是 media 子域名缓存失败,而是:

迁移 media 子域名后,WordPress 旧文章正文中保存的历史图片 URL 不会自动更新。

最终处理逻辑是:

Plaintext
1. EdgeOne 仍然有 301
2. 筛选发现 301 集中在 /wp-content/uploads/ 图片路径
3. curl 确认 301 是 EdgeOne 边缘直接返回,没有回源
4. curl 确认 media 子域名图片可以正常 Cloudflare HIT
5. 检查旧文章 HTML,发现仍然输出旧图片地址
6. 用 Better Search Replace dry run 检查完整旧图片 URL
7. 备份数据库
8. 正式替换完整旧图片 URL
9. 清理 W3 Total Cache
10. 重新验证旧文章前台 HTML 已经不再输出旧图片地址

这次真正需要替换的是:

Plaintext
https://www.shuijingwanwq.com/wp-content/uploads/

替换为:

Plaintext
https://media.shuijingwanwq.com/

而不是直接把所有:

Plaintext
/wp-content/uploads/

都替换掉。

十一、后续观察

替换完成后,EdgeOne 中的 301 不会立刻归零。

原因包括:

Plaintext
搜索引擎仍然可能请求旧图片 URL;
浏览器缓存中可能还保存旧地址;
外部引用可能仍然访问旧图片路径;
EdgeOne 的统计数据也有时间窗口延迟。

但后续真实用户访问旧文章时,页面 HTML 已经直接输出 media 子域名图片地址,不再先请求旧的 /wp-content/uploads/,因此由文章页面触发的 301 应该会逐步下降。

对我来说,这次排查也再次提醒了一点:

WordPress 的媒体 URL 配置影响的是未来新插入的图片,不会自动修改历史文章正文。

如果站点运营时间比较长,历史文章数量比较多,在迁移图片域名、CDN 域名、静态资源域名时,一定要把历史文章正文中的固定 URL 一起纳入排查范围。

EdgeOne 流量成本排查:将 WordPress uploads 静态资源迁移到 Cloudflare media 子域名

需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理