CDN会缓存404响应因其默认对错误状态码(如404、403、500)进行短时缓存以减轻源站压力,导致页面恢复后用户仍见“Not Found”;需在后端响应中强制添加Cache-Control: no-store等头禁用缓存,并在CDN层刷新对应路径而非仅URL。

CDN 缓存了旧的 404 响应,用户访问本该恢复的页面仍看到“Not Found”,这不是页面真丢了,而是 CDN 把错误状态码也记住了——它把 404 当成一个合法响应缓存下来了,且默认不主动过期。
为什么 CDN 会缓存 404?
CDN 的缓存策略通常基于 HTTP 状态码和响应头。很多 CDN(如 Cloudflare、腾讯云、又拍云)默认会对 404、403 甚至 500 响应做短时间缓存(比如 1–10 分钟),目的是减轻源站压力。但一旦你修复了路径、上线了新资源或改好了路由,这个“已缓存的 404”就会继续返回给用户,造成“明明存在却打不开”的假象。
PHP 后端怎么避免生成可缓存的 404?
关键不是等 CDN 刷新,而是让后端不给 CDN 缓存的机会:确保真实 404 响应带明确的禁止缓存头,尤其在开发/上线过渡期。
- 在自定义 404 页面逻辑里加两行:
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); header('Expires: Wed, 11 Jan 1984 05:00:00 GMT'); - 不要用
header('HTTP/1.1 404 Not Found')单独发送状态码就结束;必须配合上述缓存控制头,否则 Nginx / CDN 可能按默认规则缓存它 - 若用了框架(如 Laravel),检查是否在
App\Exceptions\Handler::render()中统一处理 404;这里同样要补上Cache-Control头,否则中间件可能漏掉 - 注意:有些 CDN(如阿里云全站加速)会忽略 PHP 输出的头,只认源站 Nginx 配置;此时需在 Nginx 的
location块中对 404 响应强制设头:error_page 404 = @notfound; location @notfound { add_header Cache-Control "no-store, no-cache"; internal; }
CDN 层面必须刷新,不能只清资源 URL
单纯调用 RefreshCdnUrl 刷新某个 HTML 地址没用——因为出问题的不是那个文件,而是 CDN 对 GET /xxx 这个请求路径返回并缓存了 404。必须刷新“路径本身”,或清空该路径的缓存条目(含状态码)。
立即学习“PHP免费学习笔记(深入)”;
- 腾讯云 CDN:API 接口
RefreshCdnUrl支持刷新单个 URL,但需确认该 URL 当前返回的是 404;刷新后,下次请求会回源,若源站已修复,就自然拿到 200 - Cloudflare:在缓存规则里添加一条「缓存忽略」规则,匹配对应路径,设置
Cache Level = Bypass,临时绕过缓存,验证源站是否正常 - 又拍云:使用
purge接口时,传入的urls必须是完整请求路径(如https://example.com/api/v2/user),且需确保 API 调用时携带了正确的认证信息和时间戳签名 - 通用技巧:用
curl -I https://your-domain.com/broken-path先确认当前返回的确实是404且带X-Cache: HIT(说明是 CDN 返回的),再执行刷新;刷新后再次-I检查是否变成X-Cache: MISS和200
上线时预防比补救更重要
最省事的方式,是在部署新版本前就阻断 404 被缓存的可能。
- 静态资源(JS/CSS/图片)上线时,强制更新文件名或加版本哈希(如
app.a1b2c3.js),这样新链接天然不命中旧缓存,连带规避了旧 404 路径被复用的风险 - HTML 页面启用
Cache-Control: no-cache或用ETag,确保每次都能校验源站内容是否变化;哪怕 HTML 里引用了新 JS,也能触发重新拉取 - 灰度发布时,先上线资源文件,再上线 HTML/路由配置——避免 HTML 已上线但引用的 JS 还未部署,导致浏览器报
404,进而被 CDN 缓存 - 所有 CDN 控制台里,检查「错误状态码缓存时间」设置项(常叫
Cache Error Response或Stale Error Cache),生产环境建议设为0或Off,开发期更应关闭
真正麻烦的从来不是“怎么刷新”,而是没意识到 CDN 会把 404 当正经内容缓存;等用户反馈“点不开”,往往已经缓了几十分钟——所以部署前后,记得用 curl -I 看一眼关键路径的真实响应头和状态码。











