sub_filter需满足响应为text/html、禁用压缩、开启缓冲、设置sub_filter_once off等条件才能生效,支持多条指令替换绝对URL、根路径及base标签等内容。

使用 sub_filter 指令可以在 Nginx 代理层对后端返回的 HTML 内容做实时字符串替换,从而修正页面中硬编码的绝对路径(如 http://old-domain.com/css/app.css 或 /static/js/main.js),避免前端重新构建或修改源码。它适用于反向代理场景,但需注意生效条件和常见陷阱。
确保 sub_filter 生效的前提条件
sub_filter 不是“开箱即用”,必须满足以下几点才能正常工作:
- 响应内容类型必须是
text/html(或显式匹配的 MIME 类型),Nginx 默认只对text/html启用;可通过sub_filter_types扩展,例如:sub_filter_types text/css application/javascript; - 响应不能被压缩(gzip / brotli),否则原始 HTML 已被编码,无法匹配文本。需在 proxy 配置中关闭后端压缩:
proxy_set_header Accept-Encoding ""; - 响应体不能是流式传输(如
Transfer-Encoding: chunked且未缓存),建议开启sub_filter_last_modified off;并配合proxy_buffering on;确保完整接收后再处理 -
sub_filter默认只替换**第一次匹配项**,如需全局替换,必须加sub_filter_once off;
修正不同类型的硬编码路径
根据路径形式选择对应策略,通常需组合多个 sub_filter 指令(Nginx 允许多条):
-
替换协议+域名的绝对 URL:
sub_filter 'https://legacy.example.com' 'https://new.example.com'; -
替换根路径开头的绝对路径(/static/ → /cdn/static/):
sub_filter '/static/' '/cdn/static/';(注意结尾斜杠防误替) -
替换相对路径中的 base href(常见于单页应用):
sub_filter '' ' '; -
同时修正 script/src 和 link/href 中的路径:需确保 HTML 格式规范,如:
sub_filter 'src="/js/' 'src="/cdn/js/';(注意引号和空格边界)
典型配置示例(含关键防护)
以下是一个生产可用的 proxy + sub_filter 片段:
location / {
proxy_pass https://backend;
proxy_set_header Host $host;
<pre class="brush:php;toolbar:false;"># 关键:禁用后端压缩,确保能匹配明文
proxy_set_header Accept-Encoding "";
# 开启缓冲,确保 sub_filter 有完整响应体
proxy_buffering on;
proxy_buffers 8 128k;
proxy_busy_buffers_size 256k;
# 启用 sub_filter 并支持多类型
sub_filter_types text/html text/css application/javascript;
sub_filter_once off;
# 替换域名、静态路径、base 标签
sub_filter 'https://old.site' 'https://new.site';
sub_filter '/static/' '/assets/';
sub_filter '<base href="/">' '<base href="/subpath/">';
# 可选:添加响应头提示已处理
sub_filter_last_modified off;
add_header X-Sub-Filtered "true";
}
调试与验证技巧
遇到不生效时,按顺序检查:
- 用
curl -H "Accept-Encoding: identity" http://your-proxy/绕过浏览器缓存和压缩,确认原始响应是否含目标字符串 - 查看 Nginx error log,搜索
sub_filter相关警告(如 MIME 不匹配、buffer 不足) - 临时加
add_header Content-Encoding "";强制清除编码头,排除 gzip 干扰 - 用
sub_filter 'foo' 'bar'; sub_filter 'bar' 'baz';测试链式替换是否被覆盖(Nginx 是顺序执行,后一条会作用在前一条结果上)











