源站能打开,走CDN却404?回源Host与缓存排查方法
源站地址直接访问正常,域名接入CDN后却显示404。
遇到这种情况,很多人的第一反应是:“CDN没有回源成功。”
但404和502、504不一样。502、504通常意味着CDN没有正常拿到源站响应,而404往往说明请求已经被某一层接收,只是这一层认为你要访问的资源不存在。
问题可能发生在CDN边缘节点,也可能来自源站。更常见的情况是:CDN确实回源了,但回源时携带的域名、路径、协议或者端口与直接访问源站时不一样。
所以,排查的第一步不是清理缓存,也不是反复修改DNS,而是先确认:
这个404到底是谁返回的?
先判断404来自CDN还是源站
一次完整的访问大致经过下面几层:
浏览器 → CDN边缘节点 → CDN回源配置 → Web服务器 → 网站程序或对象存储
任何一层都可能返回404。
现象 | 更可能出现问题的位置 |
|---|---|
所有地区一直返回相同404 | 回源Host、URL路径或源站配置 |
只有部分地区返回404 | 个别CDN节点缓存、区域配置或调度差异 |
首页正常,图片或JS返回404 | 静态资源路径、缓存规则或对象存储 |
刷新缓存后短暂恢复 | CDN缓存了旧的404响应 |
直接用源站IP访问正常,域名回源404 | Host、SNI或虚拟主机配置 |
原始URL正常,带参数或特殊字符时404 | 参数忽略、URL重写或编码问题 |
只有POST、PUT请求404 | 请求方法、API路由或边缘规则 |
CDN页面和源站404页面样式不同 | 可能是CDN边缘节点直接返回 |
可以先查看响应头:
curl -I https://www.example.com/test.jpg为了看到跳转过程及更完整的信息,可以使用:
curl -sS -L -D - -o /dev/null \
https://www.example.com/test.jpg重点观察这些响应头:
HTTP/2 404
server:
via:
age:
x-cache:
cf-cache-status:
x-request-id:
x-served-by:不同CDN使用的响应头不一样,不能只凭某一个字段下结论。不过,如果响应中出现明显的缓存状态、边缘节点编号或CDN请求ID,至少可以确定请求经过了CDN。
还可以使用CDNChart的CDN检测工具,先确认域名当前解析到了哪家CDN、使用了哪些CNAME和节点IP,避免实际上访问的还是旧节点或其他加速服务。
最常见的问题:CDN回源时使用了错误的Host
一台源站服务器经常同时托管多个网站,例如:
www.example.com
api.example.com
static.example.comNginx、Apache以及其他Web服务器通常根据HTTP请求中的Host判断应该把请求交给哪个站点。
假设源站上真正配置的网站是:
www.example.com但CDN回源时发送的却是:
Host: origin.example.com或者直接发送源站IP作为Host,Web服务器就可能把请求分配给默认站点。默认站点找不到对应文件,返回的自然是404。
这也是“源站可以打开,走CDN却404”最常见的原因之一。
需要进入CDN控制台检查以下配置:
回源Host填写的是什么
回源Host是加速域名、源站域名还是源站IP
源站Web服务器是否配置了对应的虚拟主机
HTTPS回源时使用的SNI域名是否正确
多个业务域名是否共用了同一条回源配置
如果网站实际依赖www.example.com识别虚拟主机,回源Host通常也应该设置为这个域名,而不是随意填写源站地址。
不要直接访问HTTPS源站IP进行对比
不少人会直接打开:
https://203.0.113.10/test.jpg然后发现可以访问,就认定源站没有问题。
这种测试并不可靠。
HTTPS连接除了HTTP Host,还涉及TLS握手阶段的SNI。直接访问IP时,源站可能返回默认证书或默认虚拟主机,与CDN实际回源的请求并不相同。
更准确的方法是使用curl --resolve,让请求连接到指定源站IP,同时保留原来的域名、Host和TLS SNI:
curl -sS -D - -o /dev/null \
--resolve www.example.com:443:203.0.113.10 \
https://www.example.com/test.jpg这里需要替换:
www.example.com 你的加速域名
203.0.113.10 你的源站IP
/test.jpg 出现404的实际路径然后再测试经过CDN的结果:
curl -sS -D - -o /dev/null \
https://www.example.com/test.jpg把两次结果放在一起比较。
如果指定源站IP时返回200,经过CDN时返回404,问题大概率位于CDN缓存、回源Host、URL改写或者源站选择配置。
如果两边都是404,问题通常已经落到源站的网站配置、程序路由或文件路径上。
对于只提供HTTP的源站,也可以这样测试:
curl -sS -D - -o /dev/null \
-H "Host: www.example.com" \
http://203.0.113.10/test.jpg回源路径被改了,也会出现404
浏览器访问的路径不一定就是源站最终收到的路径。
例如用户请求:
https://www.example.com/images/logo.pngCDN回源时可能因为规则配置,变成:
http://203.0.113.10/static/images/logo.png也可能错误地变成:
http://203.0.113.10/images/images/logo.png常见原因包括:
配置了回源路径前缀
CDN边缘规则进行了URL重写
源站Nginx又执行了一次
rewrite对象存储路径与网站URL不一致
尾部斜杠处理不一致
URL大小写不一致
特殊字符被重复编码
CDN忽略或保留查询参数的规则不正确
Linux文件路径通常区分大小写:
/Images/Logo.png
/images/logo.png在某些本地开发环境中,这两个地址可能都能打开;部署到Linux源站或对象存储后,它们却是两个不同的路径。
因此,排查时不要只测试首页。应该复制发生404的完整URL,包括路径、文件名、扩展名和查询参数,再分别测试CDN和源站。
CDN可能缓存了之前的404
CDN缓存的不一定只有200响应。
如果资源还没有上传时,CDN节点向源站请求过一次,源站当时返回404,而CDN又配置了错误状态码缓存,那么这个404可能会继续留在节点上。
后来即使源站已经上传了文件,用户访问时仍可能得到之前缓存的404。
可以通过响应头中的Age、缓存状态或厂商特有字段寻找线索:
curl -I https://www.example.com/test.jpg例如:
HTTP/2 404
Age: 1860
X-Cache: HIT这类结果通常说明404并不是刚从源站获取的,而是命中了节点中的缓存副本。
需要采取的操作包括:
在CDN控制台刷新这个具体URL。
检查404状态码的缓存时间。
确认缓存键是否包含查询参数。
检查不同目录是否应用了不同缓存规则。
刷新后从多个地区重新测试。
HTTP规范允许部分状态码在满足条件时被缓存,因此不能默认认为404一定不会进入缓存。关于404状态的语义,可以参考HTTP 404规范说明。
不要一出现404就刷新整个域名。先刷新一个具体URL,确认问题确实与缓存有关,避免没有必要的大范围回源。
为什么只有部分地区返回404?
如果北京访问正常,广州404;电信正常,移动404,这种情况一般不是单一的源站文件缺失。
更值得检查的是:
部分CDN节点仍保存旧404缓存
不同地区被调度到了不同CDN厂商
国内和海外使用了不同源站
不同线路配置了不同回源Host
某个区域的配置还没有同步完成
多源站之间的文件或版本不一致
灰度发布只更新了部分服务器
DNS仍在返回已经下线的旧节点
这时,单独在自己电脑上测试意义有限。可以使用CDNChart的网站测速工具,从不同地区和运营商观察状态码、解析结果和访问表现。
测试时最好固定同一个URL,并记录:
测试时间
测试地区
网络运营商
解析到的节点IP
HTTP状态码
响应头
响应内容
CDN请求ID
如果404集中出现在同一个节点IP或同一个区域,定位范围就会小很多。
多源站配置也容易制造“随机404”
不少网站配置了多个源站:
源站A:203.0.113.10
源站B:203.0.113.20如果文件只同步到了源站A,那么用户访问结果就可能出现:
第一次:200
第二次:404
第三次:200看起来像CDN不稳定,实际上是两个源站的内容不一致。
可以分别指定每个源站IP测试:
curl -sS -D - -o /dev/null \
--resolve www.example.com:443:203.0.113.10 \
https://www.example.com/test.jpgcurl -sS -D - -o /dev/null \
--resolve www.example.com:443:203.0.113.20 \
https://www.example.com/test.jpg如果一个返回200,另一个返回404,就不需要继续在CDN节点上兜圈子了。应该检查文件同步、版本发布、共享存储或者源站健康检查策略。
动态网站还要检查应用路由
对于WordPress、Laravel、Next.js、Java Spring等动态网站,404不一定由Nginx直接返回,也可能是应用程序返回的。
例如:
CDN回源时丢失查询参数
回源Host不在应用允许的域名列表中
应用根据域名加载不同租户
伪静态或路由重写没有生效
CDN把POST请求错误转换成GET
带语言、地区或版本前缀的路径被改写
应用发布后路由缓存没有更新
可以对比CDN和源站返回的404页面内容:
curl -sS https://www.example.com/test-path \
-o cdn-404.htmlcurl -sS \
--resolve www.example.com:443:203.0.113.10 \
https://www.example.com/test-path \
-o origin-404.html然后比较两个文件:
diff cdn-404.html origin-404.html如果页面内容、响应头和请求ID都一致,404很可能来自源站应用;如果两者完全不同,则更可能是CDN边缘规则或不同虚拟主机返回的结果。
一套更省时间的排查顺序
实际排查时,可以按照下面的顺序进行。
先请求经过CDN的完整URL:
curl -sS -D cdn-headers.txt \
-o cdn-body.html \
https://www.example.com/problem-path再绕过CDN请求真实源站:
curl -sS -D origin-headers.txt \
-o origin-body.html \
--resolve www.example.com:443:203.0.113.10 \
https://www.example.com/problem-path比较状态码、响应头和页面内容:
diff cdn-headers.txt origin-headers.txt
diff cdn-body.html origin-body.html如果源站200、CDN 404,继续检查:
CDN是否命中了旧404缓存
回源Host和SNI是否正确
CDN是否修改了URL
CDN是否选择了另一个源站
边缘函数或规则是否直接返回404
如果源站和CDN都是404,继续检查:
源站虚拟主机
Nginx或Apache日志
文件实际路径
应用路由
发布版本
对象存储中的文件名和权限
curl各项参数的详细说明可以查看curl官方手册。
修改配置后,不要只测试一次
改完回源Host或者清理缓存后,自己的电脑能打开,并不代表问题已经完全解决。
至少还要确认:
不同地区是否都恢复
电信、联通、移动是否一致
IPv4和IPv6结果是否一致
首页和出错的具体资源是否都正常
无参数URL和带参数URL是否一致
多个源站是否都返回200
旧节点是否仍在DNS结果中
如果问题只在某些网络出现,保留节点IP、测试时间和响应中的请求ID,再提交给CDN厂商。相比只说“网站偶尔404”,这些信息更容易让技术支持查到具体节点日志。
常见问题
源站返回200,CDN一定有问题吗?
不一定。首先要确认源站测试是否保留了正确的Host和HTTPS SNI。直接访问源站IP得到200,并不能证明CDN使用相同请求条件回源。
清理CDN缓存后还是404怎么办?
检查回源Host、回源路径、协议、端口和源站选择。缓存刷新只能解决旧响应被缓存的问题,不能修复错误的回源配置。
为什么首页正常,某些图片却404?
通常与文件路径、大小写、缓存规则、对象存储目录或静态资源域名有关。应使用具体图片URL分别测试CDN和源站,而不是只测试首页。
为什么404一会儿出现、一会儿消失?
优先检查多源站内容是否一致,以及不同CDN节点是否缓存了不同版本。把每次请求解析到的节点IP和响应头一起记录下来,往往能快速发现规律。
CDN返回404会影响SEO吗?
如果搜索引擎抓取重要页面时持续收到404,该页面可能逐渐退出索引。修复后应确认页面稳定返回200,并检查站内链接、站点地图和canonical是否仍然指向正确URL。偶发的节点404也不能忽略,因为搜索引擎爬虫可能正好被调度到异常节点。
- CDN访问404
- 源站正常CDN 404
- CDN回源404
- 接入CDN后404
- CDN Host配置
- CDN缓存404
- CDN回源失败