CDN与Nginx缓存有效期冲突本质是响应头控制权混乱,需通过curl逐层检查Cache-Control等头部,确认CDN是否覆盖源站头、Nginx是否透传错误头,并统一用add_header显式注入标准缓存指令。

CDN缓存与Nginx源站缓存有效期“打架”,本质是两层缓存对同一资源设置了冲突的过期策略,导致用户看到旧内容、刷新不生效,或CDN频繁回源。关键不在“谁设得长”,而在于“谁说了算”——HTTP响应头中哪个缓存指令最终被CDN和浏览器采纳。
看响应头链路:从浏览器一路追到源站
用 curl -I 请求目标URL(建议加 -H "Cache-Control: no-cache" 绕过本地缓存),逐层检查响应头:
-
浏览器收到的响应头:关注
Cache-Control、Expires、Age、X-Cache(CDN自定义)、X-Cache-Status(Nginx自定义) -
CDN节点返回的头:若CDN有边缘日志,查其
X-Cache: HIT时的Age值,再比对Cache-Control: max-age=xxx,可反推CDN实际采用的TTL -
Nginx源站响应头:在Nginx配置中确认是否用了
proxy_hide_header Cache-Control或add_header Cache-Control ...——若Nginx回源时把后端的private或短max-age直接透传,CDN很可能直接继承
查CDN控制台的缓存规则优先级
不同CDN厂商对响应头的处理逻辑不同,常见覆盖顺序如下(以阿里云、腾讯云、Cloudflare为参考):
- CDN控制台中按路径/文件类型设置的「强制缓存规则」优先级最高(例如:/static/*.js → TTL=31536000)
- 其次才是源站返回的
Cache-Control和Expires,但部分CDN默认只认max-age,忽略public/private - 若CDN开启「忽略查询参数」或「标准化URI」,则
?v=1.2.3不影响缓存键,但源站若未统一清理参数,仍可能造成Nginx层缓存键不一致
核对Nginx是否在回源时“交出了控制权”
Nginx作为源站,不是被动吐头,而是可以主动干预CDN行为:
- 避免透传后端错误头:
proxy_hide_header Cache-Control;+proxy_hide_header Expires;+proxy_hide_header Set-Cookie; - 用
add_header Cache-Control "public, max-age=3600";显式注入标准指令(注意:需确保未被expires指令重复覆盖) - 对静态资源路径(如
/static/)禁用proxy_cache,改用expires+add_header,让CDN直取Nginx文件系统,避免Nginx代理缓存与CDN缓存双重管理
做一次“缓存一致性快照”测试
选一个典型资源(如 /app.css),在同一时间点执行三步验证:
- 在用户侧 curl 获取响应头,记录
Cache-Control和Age - 在CDN后台查该资源在边缘节点的缓存状态与最后更新时间
- 登录Nginx服务器,检查该请求是否命中
proxy_cache(看$upstream_cache_status日志),并确认对应缓存文件的stat修改时间
三者时间差超过5秒,就说明某一层缓存没对齐;若CDN的 Age 远大于Nginx缓存文件的修改时间,大概率是CDN用了自己的TTL而非源站头。


















