现场是这样的。源站对 If-Modified-Since 返回 304,CDN 边缘却给客户端回 200 全量,命中率显示 0,每次蜘蛛抓取都要重新下载 120KB。
中间走过弯路,把「源站 ETag 每次请求都变,条件请求永远不命中」当成主因,改完现象没变。
原因不止一个,得分开看。CDN 没有透传 If-None-Match,回源时总是拿全量;边缘把 304 转成 200,缓存副本没有更新;缓存 TTL 设成 0,边缘根本不保留副本。
第一件事是看响应里的缓存相关头
curl -sI https://www.example.com/post-1/ | Select-String "ETag|Last-Modified|Age"
接着确认源站 ETag 是否稳定
curl -sI https://www.example.com/post-1/ | Select-String ETag; curl -sI https://www.example.com/post-1/ | Select-String ETag
再往下让 CDN 透传条件请求头
proxy_set_header If-None-Match $http_if_none_match;
等前面都确认过,再把 HTML 的 TTL 调到合理值
add_header Cache-Control "public, max-age=600";
同样的操作我在测试机上先走了一遍,线上只做验证过的部分。
这台环境是别人交接的,不少默认值被动过,只能一项项核。
别只看报错消失,验证要多做一步。边缘缓存命中率升到八成以上,蜘蛛抓取时能拿到 304,下载量明显下降。
304 省的是带宽不是抓取次数,但每次全量下载会挤占抓取预算。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
