If-Modified-Since是HTTP请求头而非Nginx指令,调优关键是保障其在协商缓存中稳定生效:确保Last-Modified准确(避免构建/CDN/Windowsmtime问题)、关闭默认ETag防干扰、必要时用if_modified_since off禁用协商并转向内容哈希+immutable强缓存。

“if_modified_since”不是Nginx的配置指令,而是HTTP协议中由浏览器自动发送的请求头(If-Modified-Since)。所谓“调优”,本质是让这个头在协商缓存链路中稳定、高效地起作用——目标不是让它更频繁触发,而是让它更少被误判、更少被绕过、更少与其它机制冲突。
确保 Last-Modified 响应头可靠生成
协商缓存的前提是服务器能准确告诉浏览器“资源最后改于何时”。Nginx默认对静态文件(.js/.css/.png等)基于文件系统mtime自动设置Last-Modified,但以下情况会破坏其可信度:
- 构建产物(如Webpack输出)部署时未保留原始修改时间,导致集群各节点mtime不一致,同一资源在不同机器上返回不同Last-Modified值
- CDN或边缘节点默认抹除或覆盖
Last-Modified头,需显式开启透传(如Cloudflare的“Cache Respect Origin”或阿里云CDN的“回源带Last-Modified”) - Windows服务器文件系统mtime精度为秒级,高频构建场景下易出现“已更新但时间未变”或“未更新但时间漂移”,建议生产环境统一使用Linux主机
避免 ETag 干扰 If-Modified-Since 的单一判断路径
当客户端同时发送If-Modified-Since和If-None-Match(ETag)时,RFC规定服务器必须优先校验ETag。这看似合理,实则埋下隐患:
- 部分旧版代理或CDN只转发
If-Modified-Since,若此时ETag因后端逻辑或CDN重写而失效,协商就退化为不可靠的时间比对 - Nginx默认开启ETag(
etag on),且其弱ETag由文件大小+mtime拼接而成,与Last-Modified强耦合,反而放大mtime不一致问题 - 推荐做法:静态资源明确关闭ETag,用
etag off;配合Last-Modified单一信源;若需双重保障,应由后端生成内容哈希型ETag(如MD5/SHA256),而非依赖文件元数据
用 if_modified_since off 主动退出协商,转向强缓存兜底
与其花力气修复mtime一致性或对抗CDN干扰,不如减少对协商缓存的依赖:
- 在Nginx location块中添加
if_modified_since off;,可彻底禁用Nginx层的If-Modified-Since比对逻辑,把控制权交给后端或强缓存策略 - 配合内容哈希化文件名(如
app.f3a7b2.js),对这类资源配置长期强缓存:expires 1y;+add_header Cache-Control "public, immutable"; -
immutable是关键:它向浏览器声明“此URL内容永不变”,浏览器在过期前连If-Modified-Since和If-None-Match都不会发,真正零协商开销
分层验证:别只看头,要看行为
是否生效不能只查响应头是否存在Last-Modified,必须实测完整生命周期:
- 首次请求某JS文件,在DevTools Network面板确认响应含
Last-Modified: Wed, 01 Jan 2025 00:00:00 GMT及Cache-Control: public, max-age=31536000 - 手动清空浏览器缓存或等待缓存过期后刷新,检查新请求的Request Headers是否含
If-Modified-Since,且值与上一次的Last-Modified完全一致 - 此时若资源未改动,Nginx应返回
304 Not Modified,Response面板Size显示“cached”或“304”,无响应体;若返回200且带完整body,说明协商失败,需回溯mtime、ETag或CDN配置


















