nginx sub_filter:替换了 HTML,也改变了缓存行为

发布时间:2026/10/14 17:11:57
nginx sub_filter:替换了 HTML,也改变了缓存行为 一次页面排查中我们遇到这样的现象浏览器打开的是旧 HTML里面引用的带哈希 JavaScript 文件已经不在当前部署中。重启浏览器后页面恢复正常。检查响应时又发现一个容易忽略的差异静态资源有ETag和Last-ModifiedHTML 却没有连Cache-Control也没有。为什么同一台 nginx 会返回不同的响应头线索藏在sub_filter中。但要理解缓存风险还需要分清两件事响应有没有验证器以及缓存能否直接复用它。sub_filter 做了什么sub_filter用来替换响应正文中的字符串。它属于ngx_http_sub_module模块源码文件名则是ngx_http_sub_filter_module.c。它做的是忽略大小写的字符串匹配不解析 HTML也不是正则替换。nginx 官方模块文档例如同一份前端构建需要服务多个站点分享卡片的图片地址又需要包含站点域名。构建时可以写入占位符metapropertyog:imagecontent__SITE_ORIGIN__/share.pngmetanametwitter:imagecontent__SITE_ORIGIN__/share.pngnginx 在发送 HTML 前替换它location / { sub_filter __SITE_ORIGIN__ https://$site_host; sub_filter_once off; try_files $uri $uri.html /index.html; }这里的$site_host是示例变量需要另行定义。用于公开站点时应通过允许的域名列表选择值未知域名使用固定回退值。仅检查字符串符合 DNS 格式不能证明域名可信直接使用任意请求 Host可能把攻击者控制的地址写入分享标签。sub_filter_once默认是on每条规则只替换一次。占位符出现在两个标签中因此这里使用off。默认处理类型就是text/html通常无需重复配置。模块也不是默认编译启用的模块部署前可用nginx -V检查构建参数。为什么 HTML 的响应头变了响应正文可能经过替换原始静态文件的长度和验证信息便不一定适合最终响应。以 nginx 官方当前源码为依据对于进入替换流程的主请求响应头过滤逻辑会清除Content-Length默认还会清除Last-Modified和ETag。nginx 官方源码有两个细节需要注意。首先清理发生在响应头处理阶段。对于进入该过滤流程的主请求nginx 不会先等正文扫描完再判断是否真的命中了占位符。因此“只有实际替换成功才删除响应头”并不准确。其次sub_filter_last_modified on的行为不是简单恢复所有原始信息。官方文档说明它保留原响应的Last-Modified源码进一步显示它会把已有的强 ETag 转成弱 ETag例如从abc变成W/abc并不会生成新的、基于替换后正文的 ETag。Content-Length仍然会被清除。弱 ETag 不保证响应逐字节一致。更不能因为它变弱就认为动态替换结果已经有了正确的版本标识。如果替换值改变而底层文件不变文件验证器可能无法反映这个变化。另外sub_filter不会主动删除Cache-Control。HTML 没有缓存策略需要继续检查add_header、继承关系及其他配置不能全部归因于正文替换。没有 Last-Modified不等于不会缓存HTTP 缓存有两个不同的问题。新鲜度决定缓存能在多长时间内直接复用响应。Cache-Control: max-age600表示有效期为十分钟。验证器帮助缓存询问服务器存下来的版本是否仍然有效常见验证器是ETag和Last-Modified。验证通过时服务器可以返回304 Not Modified省去正文传输。没有显式新鲜度时符合条件的响应可以使用启发式缓存。RFC 9111 提到缓存可以参考Last-Modified文件距上次修改时间的 10% 是一个典型比例但标准没有规定所有缓存必须使用这个算法。RFC 9111HTTP Caching§4.2.2所以一个十天前修改的文件可能被某种缓存算法视为可以直接复用一天。这只是算法示例不能当作所有浏览器的固定行为。同样移除Last-Modified不能保证浏览器或代理每次都请求服务器。它减少了一个常见的估算依据却没有建立明确的缓存约束。不同缓存实现仍可能采用不同策略。把这项副作用当作 HTML 缓存策略风险在于以后移除正文替换、修改验证器设置页面的缓存行为可能随之改变而配置里没有一句话说明原本的意图。SPA 为什么尤其容易受影响单页应用SPA的入口 HTML 通常引用带内容哈希的资源!-- 演示文件名不对应实际项目 --scriptsrc/assets/main.oldhash.js/script发布新版本后新 HTML 引用新文件名。如果浏览器仍使用旧 HTML而服务器已删除旧资源资源请求就可能失败。沿下图蓝色入口向下读问题发生在旧 HTML 与新部署之间。红色终点强调的是旧资源已删除这个条件而不是“缓存存在就必然白屏”。缓存策略之外部署也应保留一段时间的旧哈希资源。已经打开的页面可能稍后才加载旧版本的动态模块入口 HTML 的no-cache无法解决这一类请求。把 HTML 的缓存策略写清楚对于需要及时获取新版本的公共 SPA 入口可以显式设置# 示意配置将路径替换为实际部署路径。 location / { # 文件需事先存在并包含本项目的安全响应头配置。 include /etc/nginx/snippets/security-headers.conf; add_header Cache-Control no-cache always; sub_filter __SITE_ORIGIN__ https://$site_host; sub_filter_once off; try_files $uri $uri.html /index.html; }no-cache允许存储响应但要求缓存复用前成功验证。它与禁止存储的no-store不同。没有可用验证器时通常需要重新获取完整 HTML对于较小的入口文件这往往是可以接受的成本。RFC 9111no-cache这里重新引入安全响应头有明确原因在默认继承规则下只要当前location定义了自己的add_header就不再继承上层的add_header。添加缓存头时可能意外丢失 CSP 等安全响应头。nginx 1.29.3 起支持add_header_inherit merge来调整此行为但使用前要确认实际版本和现有配置避免重复添加响应头。nginx 官方响应头文档带内容哈希的资源可以采用长缓存前提是同一路径的文件内容保持不变。例如在独立的资源location中设置public, max-age31536000, immutable。缺失资源应返回真实的 404避免回退成 HTML 后被长期缓存长期策略也应只用于成功的资源响应。如果页面包含个人信息或依赖登录身份需要另行设计private或no-store策略不能直接套用公共入口的设置。配置后怎么检查先在实际容器或服务器中检查版本、编译参数与配置nginx-vnginx-Vnginx-t再使用 GET 检查最终响应。下面的域名和路由均为示例curl-sS-Dheaders.txt-opage.html https://example.com/app确认 HTML 返回Cache-Control: no-cache安全响应头仍然存在正文中的占位符已经替换。还要分别检查/index.html、实际 SPA 深层路由和哈希资源因为它们可能匹配不同的location。经过 CDN 时应分别观察源站和公开入口。新加的响应头不会自动召回所有已被视为新鲜的旧缓存已有缓存需要结合平台能力处理。替换失败时也要检查压缩。sub_filter不会自行解压 gzip 正文。代理上游可按需要使用proxy_set_header Accept-Encoding ;请求未压缩内容启用gzip_static时应确认 HTML 没有绕过替换流程直接使用预压缩文件。最终应同时检查响应头和实际正文不能仅凭配置文本判断成功。如果配置由 shell heredoc 生成还要区分两层变量nginx 变量通常需要写成\$site_host让它保留到运行时需要 shell 展开的变量则不转义。这取决于 heredoc 是否使用带引号的结束标记不能机械地给所有$加反斜杠。这次现象能说明什么重启浏览器后恢复是客户端状态可能参与故障的线索。它不能单独证明旧 HTML 来自内存缓存也不能排除 Service Worker、页面恢复、代理或其他因素。排查仍需要查看故障时的 Network 记录、响应来源和资源请求。因此我不会把这次旧页面直接归因于sub_filter。这次排查更明确的收获是正文替换和缓存策略应分别表达。sub_filter负责修改内容Cache-Control负责规定响应如何被复用部署策略负责保证旧页面仍能找到它引用的资源。参考资料nginxngx_http_sub_module 指令说明nginxsub_filter 模块官方源码nginxadd_header 与响应头继承规则RFC 9111HTTP Caching

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询