Nginx sub_filter可在反向代理层对HTML/文本响应做轻量级关键词替换与脱敏,无需修改后端;需http_sub_module支持,仅作用于text/html、text/plain等指定MIME类型,不支持正则,有流式替换、不处理压缩、无上下文解析等限制。

可以通过 Nginx 的 sub_filter 指令在反向代理网关层对后端返回的 HTML 或纯文本响应内容做轻量级、实时的关键词替换与脱敏,无需修改后端代码,适合敏感字段(如手机号、身份证号、邮箱)的前端展示层遮蔽。
启用 sub_filter 的基本前提
该功能仅在 Nginx 的 http_sub_module 模块启用时可用(主流发行版默认编译进内核,但 OpenResty 或精简版可能需手动开启)。确认方式:
- 执行
nginx -V 2>&1 | grep -o with-http_sub_module,有输出即支持 - 若无,需重新编译 Nginx 并添加
--with-http_sub_module -
sub_filter只作用于text/html和text/plain响应(可通过sub_filter_types扩展 MIME 类型)
基础关键词替换与脱敏写法
在 location 块中配置,例如将页面中所有手机号脱敏为 138****1234 格式:
location /api/ {
proxy_pass https://backend/;
sub_filter '1[3-9]\d{9}' '***';
sub_filter_types text/html text/plain application/json;
sub_filter_once off;
}
注意:sub_filter 默认只匹配字面字符串,不支持正则;如需正则替换,必须搭配 sub_filter_once off + 多条固定规则,或改用 Lua(OpenResty)实现动态脱敏。
- 推荐做法:先用后端返回结构化数据(如 JSON),再在 Nginx 层用多条
sub_filter覆盖常见格式,例如: sub_filter '"phone":"1' '"phone":"***'sub_filter '@qq.com' '@***.com'sub_filter 'idcard":"\d{17}[\dXx]' 'idcard":"***************'
注意事项与典型限制
sub_filter 是流式文本替换,不具备上下文解析能力,容易误伤或漏脱敏:
- 不处理压缩响应:务必关闭后端 Gzip(或在 Nginx 中用
proxy_buffering off配合sub_filter,否则缓冲导致替换失败) - 不支持嵌套/条件逻辑:无法判断“只有在 user 对象里才脱敏 phone 字段”,只能全局替换
- 大小写敏感:如需忽略大小写,需额外配置多条规则(
SubFilter/subfilter/SUBFILTER) - 响应体过大时性能下降:建议仅用于中小流量、HTML 页面或日志类接口,避免用于高频大 JSON 接口
进阶替代方案建议
当业务需要精准字段控制、正则动态脱敏或 JSON 结构化处理时,sub_filter 显得力不从心,可考虑:
- OpenResty + Lua:用
ngx.re.gsub对body_filter_by_lua_block中的响应体做正则替换,支持上下文提取和条件判断 - Nginx JavaScript 模块(njs):用
js_body_filter编写 JS 逻辑,更易维护 - 专用 API 网关(Kong、APISIX):内置响应重写插件,支持 JSONPath 提取+模板替换
- 后端统一中间件:虽增加开发成本,但语义清晰、可测试性强,适合长期演进

















