nginx 的 sub_filter 模块不支持 sub_filter_last_modified 指令,它仅替换响应体而不修改 last-modified 响应头,易致缓存不一致;需用 add_header 显式覆盖或屏蔽该头,并配合 cache-control 调整缓存策略。

Nginx 的 sub_filter 模块本身不支持直接配置 sub_filter_last_modified 这个指令——它并不存在于官方 Nginx 或主流模块中。你可能混淆了几个概念:Nginx 的内容替换(sub_filter)、响应头控制(如 add_header Last-Modified ...),以及缓存同步机制(如与上游 Last-Modified/ETag 的联动)。下面分几部分帮你理清关键点和可行方案:
1. sub_filter 本身不修改或同步 Last-Modified
sub_filter 只负责对响应体(body)做字符串替换,它不会读取、解析或重写响应头(包括 Last-Modified 或 ETag)。即使响应体被修改,原始的 Last-Modified 头仍保持不变,这会导致缓存不一致:客户端或 CDN 可能因旧时间戳而复用已失效的内容。
- 替换后内容已变,但
Last-Modified未更新 → 缓存命中却返回过期结果 -
sub_filter不感知上游响应头,也无法触发自动重算 - 官方模块无
sub_filter_last_modified指令,该名称属于误解或第三方补丁(极少见且不推荐)
2. 手动控制 Last-Modified 实现缓存同步
若需让替换后的内容“看起来”有新的新鲜度,最可靠方式是显式覆盖 Last-Modified 响应头,例如设为当前时间或固定值(取决于业务语义):
- 使用
add_header Last-Modified "$time_iso8601";(每次响应都用当前时间)→ 强制不缓存或短时效 - 使用
add_header Last-Modified "Wed, 01 Jan 2025 00:00:00 GMT";(固定未来时间)→ 配合expires控制缓存时长 - 注意:
add_header在location块中生效,且需确保未被其他配置覆盖;若上游已发Last-Modified,需先用proxy_hide_header Last-Modified;屏蔽
3. 更健壮的缓存同步方案:避免 sub_filter + 强缓存共存
真正解决缓存一致性问题,不建议依赖时间戳“欺骗”,而应从架构层面规避冲突:
- 对必须动态替换的内容(如域名、路径),改用前端 JS 注入或后端模板渲染,让 Nginx 只做静态缓存
- 若必须用
sub_filter,则禁用强缓存:add_header Cache-Control "no-cache, no-store, must-revalidate"; - 使用
proxy_cache_bypass $args等条件绕过缓存,仅对无参请求缓存原始内容,有替换需求时走非缓存路径 - 考虑升级到 OpenResty,用 Lua 在
header_filter_by_lua_block中读取 body hash 或时间戳,动态设置Last-Modified(需启用subrequest或提前计算)
4. 验证是否生效的小技巧
配置完成后,用 curl -I 检查响应头,确认旧 Last-Modified 已被屏蔽且新值已写入:
-
curl -I https://example.com/path→ 观察Last-Modified和Cache-Control - 对比开启
sub_filter前后响应体哈希(curl | sha256sum),确认内容确实变化 - 在浏览器开发者工具 Network 标签中查看 “Size” 是否显示 “from disk cache” 或 “from memory cache”,验证缓存行为是否符合预期
不复杂但容易忽略:缓存同步的关键不在“模拟时间戳”,而在明确内容变更与缓存策略的契约关系。用 sub_filter 就默认放弃强缓存,或主动降级缓存强度,才是稳定做法。











