if_modified_since 仅控制Nginx比对If-Modified-Since与Last-Modified的策略(exact/before/off),不提速但影响304命中率;真正提升协商效率需确保Last-Modified真实可靠、避免ETag冲突,并优先采用强缓存+哈希路径方案。

直接配置 if_modified_since 本身并不能“加快”协商缓存,它只是控制 Nginx 如何比对时间戳来决定是否返回 304。真正提升协商效率的关键,在于让这个比对过程稳定、可信、少出错——避免因时间不一致或头冲突导致本该 304 的请求被迫返回 200。
明确 if_modified_since 的三种取值含义
该指令只作用于协商缓存阶段,影响的是 Nginx 对 If-Modified-Since 请求头的处理逻辑:
-
exact(默认):服务端文件最后修改时间必须与客户端发来的
If-Modified-Since值严格相等(毫秒级),才返回 304。最保守,适合单节点或 mtime 可控环境。 - before:只要服务端文件修改时间 ≤ 客户端携带的时间,就返回 304。更宽松,能提高命中率,适合集群中各节点 mtime 略有偏差但内容一致的场景。
-
off:完全忽略客户端的
If-Modified-Since,始终返回 200。等于禁用该协商机制,一般仅用于调试或配合强缓存兜底。
确保 Last-Modified 响应头真实可靠
没有准确的 Last-Modified,if_modified_since 就是空谈。Nginx 默认会为静态文件自动设置该头,但以下情况会导致失效:
- 构建产物部署时未保留原始文件修改时间(如 Webpack 打包后所有文件 mtime 变成部署时间),多台服务器间 mtime 不一致 → 协商失败,返回 200
- CDN 或边缘节点清除了
Last-Modified头 → 浏览器收不到,后续无法发起 If-Modified-Since 请求 - 动态 HTML 页面未由后端主动设置
Last-Modified(比如基于内容哈希生成)→ Nginx 无法自动添加,协商无从谈起
避开 ETag 和 If-Modified-Since 的冲突陷阱
当客户端同时发送 If-None-Match(ETag)和 If-Modified-Since 时,RFC 要求服务器优先校验 ETag。但问题在于:
- 某些老旧代理或浏览器只发
If-Modified-Since,此时若集群节点 mtime 不一致,就会误判为“已修改” - ETag 通常由 Nginx 自动生成(基于文件大小+mtime),若 mtime 不稳,ETag 也不稳,反而加剧不一致
- 稳妥做法是在 location 块中加一句:
if_modified_since off;,把协商逻辑交给后端或彻底用强缓存替代
更优解:用强缓存 + 版本化路径绕过协商
比起依赖易受干扰的时间戳协商,对静态资源启用长期强缓存并结合内容哈希,才是省带宽、降延迟的首选:
- 构建时给 JS/CSS/图片加上内容哈希,如
app.f3a8b2.js,内容一变路径就变 - Nginx 配置中匹配这类资源,设长期缓存:
expires 1y;并加add_header Cache-Control "public, immutable"; -
immutable告诉浏览器:这个 URL 在过期前绝不会更新,连协商请求都别发 —— 直接本地读,零网络开销
不复杂但容易忽略。











