Nginx的sub_filter模块用于响应返回前对HTML等文本内容进行精确字符串替换,非正则匹配,适用于URL修正、环境标识注入等轻量场景;需启用模块、设置sub_filter_types指定MIME类型、sub_filter_once off实现全局替换,并确保响应未压缩且Content-Type匹配。

Nginx 的 sub_filter 模块用于在响应返回给客户端前,对 HTML(或其他文本类型)内容进行简单字符串替换。它不是正则匹配,而是精确的子串查找与替换,适合做轻量级页面注入、URL 修正、环境标识添加等场景。
启用 sub_filter 模块并配置基础替换
该模块默认编译进大多数官方 Nginx(1.1.6+),但需确认是否启用:
- 运行
nginx -V 2>&1 | grep -o with-http-sub-module,有输出即支持 - 若无,需重新编译时加
--with-http_sub_module
基本用法示例(替换页面中所有 http://old.com 为 https://new.com):
location / {
sub_filter 'http://old.com' 'https://new.com';
sub_filter_once off; # 默认 on(只替换第一个匹配),设为 off 可全局替换
sub_filter_types text/html; # 指定生效的 MIME 类型,默认仅 text/html
proxy_pass http://backend;
}
注意响应头与缓存的影响
sub_filter 仅处理未压缩的响应体。若后端返回 Content-Encoding: gzip,Nginx 不会解压再处理,替换将失效:
- 后端应避免对 HTML 响应开启 gzip;或使用
proxy_set_header Accept-Encoding "";禁用后端压缩 - 确保响应头含
Content-Type: text/html(或你指定的sub_filter_types中的类型) - 若启用了
proxy_buffering on(默认),Nginx 会缓冲响应后再处理,不影响 sub_filter;但若用proxy_buffering off,流式响应可能部分不被替换
链式替换与多规则处理
Nginx 不支持单个 location 内多个 sub_filter 指令叠加执行(后定义的会覆盖前一个)。如需多次替换,可用以下方式:
- 用多个
sub_filter配合sub_filter_once off,但必须按“从长到短”顺序写(避免短串先被替换导致长串无法匹配),例如:
sub_filter 'https://api.example.com/v2' 'https://api-new.example.com/v3'; sub_filter 'https://api.example.com' 'https://api-new.example.com'; # 这行要放后面
- 更可靠的做法:用多个嵌套
location或配合sub_filter_last_modified+ 条件判断(较复杂) - 如需动态值(如注入当前域名),
sub_filter不支持变量,可改用ngx_http_substitutions_filter_module(第三方增强模块)
调试与验证技巧
替换失败常见于 MIME 类型不匹配或响应被压缩。快速验证方法:
- 用
curl -I查看响应头:Content-Type和Content-Encoding - 用
curl -H "Accept-Encoding:"强制禁用压缩,再检查响应体是否被正确替换 - 临时加
add_header X-Sub-Filter "active";确认配置已加载 - 注意:替换发生在响应体生成后、发送前,所以不会影响日志中的原始 $request_body 或 $upstream_http_* 变量











