sub_filter指令用于Nginx代理中对text/html等文本响应体做静态字符串替换,支持修正硬编码路径和域名,但不支持变量插值,需配合sub_filter_types、关闭压缩,并注意避免误匹配。

sub_filter 指令可在 Nginx 代理响应体中对 HTML(或其他文本响应)进行字符串替换,适合在不修改源站代码的前提下,动态修正硬编码的绝对路径链接(如 /static/、https://www.php.cn/link/7e631293a86eb721e722395a86364fa5),使其适配当前访问域名或代理路径。
启用 sub_filter 的基本前提
该指令仅对 text/html 和 text/css 等明确声明 MIME 类型的响应生效,默认不处理压缩内容。需确保:
- 源站响应头包含
Content-Type: text/html(多数情况默认满足) - 关闭或绕过响应压缩:添加
sub_filter_once off;并禁用gzip或设置gzip_vary off;,或使用gzip_disable "msie6";避免对部分客户端压缩(更稳妥的是在 proxy 层统一解压) - 启用
sub_filter必须配合sub_filter_types显式指定支持类型,例如:sub_filter_types text/html text/css application/javascript;
修正根路径开头的硬编码资源引用
常见于静态资源路径如 或 <script src="/js/main.js"></script>。若代理路径为 /blog/,需将 /css/ 替换为 /blog/css/:
location /blog/ {
proxy_pass https://origin.example.com/;
sub_filter '/css/' '/blog/css/';
sub_filter '/js/' '/blog/js/';
sub_filter '/img/' '/blog/img/';
sub_filter_once off;
sub_filter_types text/html text/css application/javascript;
}
注意末尾斜杠一致性 —— proxy_pass 带结尾 / 表示路径重写,此时源站收到的是去前缀请求;sub_filter 中的模式应基于**返回 HTML 中实际出现的字符串**编写,而非原始请求路径。
替换跨域或旧域名的绝对 URL
当 HTML 中写死 https://www.php.cn/link/7e631293a86eb721e722395a86364fa5api/ 或 //cdn.example.com/,可通过 sub_filter 改为当前协议+主机名:
sub_filter 'https://www.php.cn/link/7e631293a86eb721e722395a86364fa5' '$scheme://$host/'; sub_filter '//cdn.example.com/' '//$host/';
注意:$scheme 和 $host 是 Nginx 内置变量,仅在 sub_filter 值中作为字面量字符串插入(不解析为变量值),所以上例实际无效。正确做法是使用固定目标,或借助 map 构建动态值:
map $host $target_origin {
hostnames;
example.com new-origin.example.com;
blog.example.com api.blog.example.com;
}
<p>location / {
proxy_pass <a href="https://www.php.cn/link/59f6437b10a9d515ab7ac4679597b52d">https://www.php.cn/link/59f6437b10a9d515ab7ac4679597b52d</a>;
sub_filter '<a href="https://www.php.cn/link/7e631293a86eb721e722395a86364fa5">https://www.php.cn/link/7e631293a86eb721e722395a86364fa5</a>' '<a href="https://www.php.cn/link/59f6437b10a9d515ab7ac4679597b52d/">https://www.php.cn/link/59f6437b10a9d515ab7ac4679597b52d/</a>';
sub_filter_once off;
sub_filter_types text/html;</p><h1>注意:此处 $target_origin 在 sub_filter 中仍为字面量,真正生效需用 escape + eval?不支持。</h1><pre class="brush:php;toolbar:false;"># 实际中建议用固定替换,或改用 Lua(nginx-lua-module)做动态替换。
}
结论:sub_filter 不支持变量插值。所有替换必须是静态字符串。动态场景需搭配 Lua 或在应用层解决。
规避替换副作用与性能提醒
sub_filter 是逐行正则匹配(非完整 DOM 解析),易误伤:
- 避免宽泛替换如
sub_filter '/api/' '/v2/api/'—— 可能改掉"/path/to/api-docs"中的子串 - 优先用带边界的模式,例如:
sub_filter 'href="/api/' 'href="/v2/api/';或sub_filter 'url(/api/' 'url(/v2/api/'; - 启用
sub_filter_last_modified on;可透传源站Last-Modified头(不影响替换逻辑,但利于缓存) - 大量替换会增加响应延迟,不建议用于高频大 HTML 页面;关键路径建议由后端渲染时注入正确 base URL
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











