文件已经上传,CDN 仍然返回 404?负缓存、缓存键与刷新路径排查指南
本内容发表于:2026-09-24 12:05:36
浏览量
1013

CDN cached 404 troubleshooting diagram

源站上的文件已经存在,直接访问源站也能返回 200,但用户通过 CDN 域名访问时仍然看到 404。这类故障经常发生在静态资源刚发布、对象存储权限刚调整,或站点从旧路径迁移到新路径之后。

404 不一定来自当前源站。CDN 节点可能缓存了此前的错误响应,也可能一直在请求另一条缓存键、另一台源站或另一条回源路径。排查时要把“浏览器看到的 404”和“源站现在是否有文件”分开验证。

先确认 404 是谁返回的

先保留完整响应头,不要只看浏览器错误页:

curl -sS -D - -o /dev/null https://static.example.com/assets/app.js
curl -sS -D - -o /dev/null https://origin.example.com/assets/app.js

重点比较状态码、Date、Age、Via、X-Cache、Server、CF-Cache-Status 等字段。不同 CDN 使用的响应头并不相同,但判断思路一致:如果 CDN 域名返回 404,源站域名返回 200,并且 CDN 响应带有命中或缓存年龄信息,错误响应被缓存的可能性很高。

若源站只能通过指定 Host 访问,测试时要模拟 CDN 的回源请求:

curl -sS -D - -o /dev/null \\
  -H 'Host: www.example.com' \\
  http://203.0.113.10/assets/app.js

直接访问 IP 返回 200,带 Host 后返回 404,通常说明虚拟主机、站点目录或回源 Host 配置不一致。此时刷新 CDN 缓存只能短暂掩盖问题。

404 为什么会被 CDN 缓存

CDN 缓存错误响应可以减少重复回源,防止不存在的路径持续打到源站。某些平台对 4xx、5xx 有默认错误缓存时间,也允许管理员单独设置。源站的 Cache-Control、CDN 缓存规则和产品默认值都可能影响保留时间。

典型过程很简单:

  1. 用户在文件发布前请求 /assets/app.js,源站返回 404。

  2. CDN 节点缓存这次 404。

  3. 文件随后上传成功,但节点仍在错误缓存有效期内继续返回旧响应。

如果 URL 曾经指向不存在的文件,或者发布流程先更新 HTML、后上传静态资源,这个时间窗口更容易出现。

排查缓存键是否一致

刷新了一个 URL,访问仍然报错,常见原因是实际请求落在另一条缓存键上。逐项检查:

  • HTTP 与 HTTPS 是否被分开处理;

  • www.example.com 与 static.example.com 是否属于不同加速域名;

  • 查询参数是否参与缓存键,例如 app.js?v=20260924;

  • URL 大小写是否不同,例如 /Assets/app.js 与 /assets/app.js;

  • 路径是否经过重写、目录补全或尾部斜杠转换;

  • Accept-Encoding、设备类型、Cookie 或自定义请求头是否进入缓存键。

可以对几个疑似变体分别取响应头:

curl -I 'https://static.example.com/assets/app.js'
curl -I 'https://static.example.com/assets/app.js?v=20260924'
curl -I 'http://static.example.com/assets/app.js'

只有带新查询参数的地址返回 200,往往说明旧缓存键仍保存着 404。这个测试适合定位,不能长期依赖随机参数绕过缓存,否则同一文件会产生大量副本。

确认文件确实发布到了 CDN 使用的源站

多源站、对象存储复制、灰度发布和容器滚动更新都会造成“有的源站有文件,有的没有”。检查 CDN 配置中的源站地址、回源端口、协议、Host 和路径前缀,再逐个验证源站。

对象存储还要区分“不存在”和“无权访问”。有些存储服务会对未授权请求返回 403,有些代理规则会把 403 改写为 404。建议同时检查:

  • 对象键是否与请求路径完全一致;

  • CDN 的源站身份或签名是否仍有效;

  • 私有桶策略是否允许当前 CDN 读取;

  • 回源路径是否重复拼接目录,例如 /static/static/app.js;

  • 最近是否切换了 Bucket、区域或源站域名。

安全地清除错误缓存

确认源站能够稳定返回 200 后,再清除对应 URL。优先做单文件刷新,范围清楚,也便于观察结果。若缓存键包含查询参数,需要按平台规则同时刷新对应变体;若大量资源都受影响,再考虑目录刷新或全站刷新。

刷新前保留一份响应头,刷新后从不同网络再次测试:

curl -sS -D before.txt -o /dev/null https://static.example.com/assets/app.js
# 在 CDN 控制台刷新该 URL
curl -sS -D after.txt -o /dev/null https://static.example.com/assets/app.js

比较状态码、Age 和缓存状态字段。首次请求可能显示 MISS,随后请求应返回 200,并逐渐变成 HIT。若刷新后仍是 404,继续查源站选择和缓存键,不要连续执行全站刷新。

调整错误缓存时间时要留出回滚路径

频繁发布新文件的站点,可以缩短 404 的缓存时间,或让特定资源目录的错误响应不被长期保留。调整前先记录原规则,只改一个测试目录,确认回源量和错误率没有异常后再扩大范围。

Nginx 反向代理若配置了错误响应缓存,也要一起检查:

proxy_cache_valid 200 10m;
proxy_cache_valid 404 30s;

这段配置表示 200 缓存 10 分钟、404 缓存 30 秒。实际值要按发布频率和回源承载能力确定。把 404 完全设为不缓存会增加无效请求对源站的压力,尤其是扫描器、爬虫或错误链接较多的网站。

修改 Nginx 前先备份配置并检查语法:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo nginx -t
sudo systemctl reload nginx

如果错误率或回源量上升,可以恢复备份配置并重新加载。

用发布流程减少旧 404

静态资源发布应先上传带版本号或内容哈希的新文件,确认 CDN 路径返回 200,再更新 HTML 或接口中的引用。旧文件保留一段时间,避免仍在缓存中的页面引用已经删除的资源。

发布完成后可以自动探测一组核心 URL,记录 CDN 和源站状态码。监控中同时观察 404 比例、回源请求量和缓存命中率。这样能区分文件漏传、权限错误、节点旧缓存和路径重写问题,减少依赖全站刷新处理局部故障。

排查这类问题时,最有用的证据是同一 URL 在 CDN 与源站上的响应差异。源站稳定返回 200、缓存键确认一致、单文件刷新后节点重新取回成功,故障才算处理完成。