Nginx 的 sub_filter 指令可对后端返回的文本响应实时替换绝对 URL,需关闭 gzip、显式设置 sub_filter_types、按顺序配置多次替换以处理协议、主机及路径映射,并注意边界匹配、缓存干扰与性能损耗。

使用 Nginx 的 sub_filter 指令可以在反向代理过程中,对后端返回的 HTML、CSS、JS 等文本响应内容进行实时字符串替换,从而将其中的绝对 URL(如 http://backend.example.com/static/)动态改写为当前代理域名下的路径(如 /static/ 或 https://proxy.example.com/static/),避免混合内容、跨域或资源 404 问题。
启用 sub_filter 并确保响应可被修改
Nginx 默认只对 text/html 类型响应启用 sub_filter,且要求响应未压缩(gzip)、未分块(chunked)、长度已知(即含 Content-Length)。因此需配合以下配置:
- 关闭后端返回的 gzip 压缩:
proxy_set_header Accept-Encoding ""; proxy_http_version 1.1;(可选,更稳妥的做法是后端禁用压缩或由 Nginx 解压后再处理) - 显式设置
sub_filter_types支持更多 MIME 类型,例如:sub_filter_types text/css text/javascript application/javascript; - 确保
sub_filter在location块中启用,且作用域明确
基础替换:将后端域名替换为代理路径
假设后端应用生成的 HTML 中包含:<script src="http://api.internal/static/app.js"></script>,而你希望它变成:<script src="/static/app.js"></script>,可配置如下:
location / {
proxy_pass https://api.internal/;
proxy_set_header Host api.internal;
<pre class="brush:php;toolbar:false;"># 关键:启用替换
sub_filter 'http://api.internal/' '/';
sub_filter_once off; # 替换全部匹配项,而非仅第一个
# 扩展支持类型
sub_filter_types text/html text/css application/javascript;}
注意:sub_filter 区分大小写,不支持正则;若后端返回 HTTPS 链接,需对应写 https://api.internal/;若需保留协议和主机(如改为 https://proxy.example.com/),则替换目标写完整地址即可。
处理相对路径干扰与多级嵌套场景
当后端混用绝对路径(https://api.internal/assets/)、协议相对路径(//api.internal/img/logo.png)和根路径(/api/v1/)时,单次替换易遗漏。建议分层处理:
- 先统一清除协议+主机:用两次
sub_filter分别处理https://api.internal和http://api.internal - 再处理协议相对链接:
sub_filter '//api.internal' '//proxy.example.com'; - 对 API 接口路径做反向映射(如后端返回
/api/v1/,但代理挂载在/backend/api/下),可用sub_filter '/api/v1/' '/backend/api/v1/';
注意:多个 sub_filter 指令按顺序执行,前序替换结果会影响后续匹配,必要时调整顺序或拆分 location 处理不同资源类型。
规避常见陷阱与增强健壮性
sub_filter 是简单字符串替换,无 HTML 解析能力,容易误伤。实际部署中应关注:
-
避免过度替换:例如把
my-api.internal中的api.internal错误替换,建议用前后缀锚定,如'src="http://api.internal/'→'src="/',或加空格/引号边界 -
响应缓存干扰:开启
proxy_cache时,sub_filter不会作用于缓存内容,需禁用缓存或使用proxy_cache_bypass $args等策略绕过 - 大响应体性能损耗:Nginx 需缓冲整个响应体再扫描替换,对 >1MB 的 HTML 可能增加延迟和内存占用;生产环境建议结合后端模板渲染优化,减少依赖代理层修正
-
HTTPS 与 HSTS 兼容:若前端强制 HTTPS,确保替换后的链接也使用
https://或协议相对写法,否则可能被浏览器拦截











