Nginx的sub_filter模块支持响应体字符串替换,适用于脱敏等场景,但仅限明文text/html等类型、不支持正则和gzip压缩内容;需显式配置sub_filter_types、gunzip on解压,并按顺序设置多条替换指令以防循环。

使用 Nginx 的 sub_filter 模块可以实现对响应体内容的实时文本替换,适合用于脱敏、品牌词替换、静态页面动态注入等场景。它工作在输出过滤阶段,轻量高效,但有明确限制——仅支持 plain text 和部分兼容 text/html 的响应,且不支持正则、不处理 gzip 压缩后的内容。
启用 sub_filter 并配置基础替换
Nginx 默认编译包含 ngx_http_sub_module,无需额外安装,但需确认配置中已启用(部分精简版发行包可能禁用)。在 location 或 server 块中添加:
sub_filter "旧词" "新词"; sub_filter_once off; # 默认为 on,只替换第一个匹配项 sub_filter_types text/html text/plain application/json; # 显式声明允许处理的 MIME 类型
注意:sub_filter 不会自动解压 gzip 响应。若上游返回 gzip 内容,需先用 gunzip on; 解压(要求 Nginx 启用 ngx_http_gunzip_module),或确保后端关闭 gzip。
多级敏感词替换与顺序控制
一个 location 中可配置多个 sub_filter 指令,Nginx 按配置顺序依次执行替换。利用该特性可构建简单敏感词过滤链:
sub_filter "张三" "***"; sub_filter "李四" "***"; sub_filter "138****1234" "138****1234"; # 手机号掩码(若原始内容已含掩码,可跳过)
- 替换是字符串精确匹配,区分大小写;如需忽略大小写,需借助第三方模块(如
nginx-substitutions-filter)或改由后端处理 - 避免循环替换:例如
sub_filter "abc" "xyz"; sub_filter "xyz" "abc"会导致不可预期结果 - 建议将高频、长词放在前面,减少后续匹配开销
配合 proxy_pass 实现动态响应改写
常见于反向代理静态资源或 API 响应时注入脱敏逻辑。示例:代理前端 HTML 页面并隐藏测试环境标识:
location / {
proxy_pass https://backend;
proxy_set_header Host $host;
<pre class="brush:php;toolbar:false;">sub_filter '<div id="env-tag">TEST</div>' '';
sub_filter '<script src="/debug.js"></script>' '';
sub_filter_once off;
sub_filter_types text/html;}
- 务必设置
sub_filter_types匹配实际响应类型,否则不会触发替换 - 若后端返回
Content-Encoding: gzip,必须加gunzip on;,否则 sub_filter 无效果 - 替换内容含特殊字符(如
/、;)时,注意 Nginx 配置语法转义,必要时用引号包裹
调试与验证技巧
替换失败常见原因包括 MIME 类型不匹配、gzip 未解压、指令作用域错误。快速验证方法:
- 用
curl -I查看响应头中的Content-Type和Content-Encoding - 临时关闭 gzip:
proxy_set_header Accept-Encoding "";+gunzip on;确保明文处理 - 开启 Nginx 错误日志
error_log /path/to/log debug;,搜索sub filter相关日志行 - 用浏览器开发者工具检查 Network → Response,确认原始响应是否含待替换文本

















