etag on; curl -I https://www.example.com/app.css curl -sI -H 'If-None-Match: "8f3c2"' https://www.example.com/app.css | head -1
浏览器明明发了 If-None-Match,CSS 每次还是 200 并重新下载 180KB,响应里没有 ETag。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。
原因不复杂,配置里写了 etag off,或者上游把 ETag 头过滤掉,Nginx 没有可比较的版本标识。Last-Modified 精度只到秒,文件频繁更新时也判不出来。
「静态文件 304 失效」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。改完隔一天再看一次,当场正常不代表能稳住。
测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。
日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
处理上按这个顺序:确认 etag 是 on 且没有被 add_header 覆盖;用 curl -I 看响应里同时有 ETag 和 Last-Modified;代理场景检查是否透传了这两个头;带 If-None-Match 再请求一次确认返回 304。
改完只确认一件事:第二次请求返回 304 Content-Length 为 0 浏览器不再重复下载。
