sub_filter 可处理 https 响应体中的硬编码资源地址,但需 nginx 终止上游 https 连接以获取明文内容,并配置 sub_filter_once off、sub_filter_types 指定 mime 类型、禁用 gzip 或启用 gunzip,且仅支持纯文本替换,不解析 html 结构或处理二进制内容。

sub_filter 指令本身不能直接处理 HTTPS 响应体中的硬编码资源地址(如 https://example.com/js/app.js),因为它仅对 Nginx 代理返回的响应体文本做简单字符串替换,且默认不处理 HTTPS 流量——Nginx 作为反向代理时,若上游是 HTTPS,它解密后才能看到明文响应体,而 sub_filter 正是作用于这个解密后的响应体。
前提:必须启用 SSL 解密代理(即「HTTPS 反向代理」)
要让 sub_filter 生效,Nginx 必须终止上游 HTTPS 连接,即配置 proxy_pass https://... 并提供可信证书信任链(如通过 proxy_ssl_trusted_certificate 或关闭验证 proxy_ssl_verify off)。只有这样,Nginx 才能拿到明文 HTML/CSS/JS 内容,进而用 sub_filter 修改其中的 URL。
- 确保
sub_filter在location块中启用,且proxy_pass指向 HTTPS 后端 - 添加
sub_filter_once off(默认为 on),否则只替换第一个匹配项 - 开启
sub_filter_types *或显式列出text/html text/css application/javascript,否则仅处理 text/html - 注意:sub_filter 不支持正则、不解析 HTML 结构,纯文本替换,故需确保目标字符串唯一、边界清晰(例如加引号或路径前缀)
典型场景:将第三方 CDN 地址重写为内网代理路径
假设原始 HTML 中有:<script src="https://cdn.example.net/v1/app.js"></script>,你想将其改为走 Nginx 本地代理(避免跨域/CSP 问题或统一审计):
- 在 location 中配置:
sub_filter 'https://cdn.example.net/' '/cdn/'; - 同时配一个内部 location 处理 /cdn/ 请求:
location /cdn/ { proxy_pass https://cdn.example.net/; } - 注意斜杠结尾与路径拼接一致性;建议源串带协议+域名+尾部斜杠,目标串用相对路径或绝对路径前缀,避免误替换
关键限制与规避技巧
sub_filter 对压缩响应(gzip)无效——必须禁用上游 gzip 或在 Nginx 解压后再处理:
- 上游若返回
Content-Encoding: gzip,Nginx 默认不自动解压,sub_filter 将跳过;需添加proxy_buffering on;和gzip off;(或启用gunzip on;配合gzip_disable) - JavaScript 中的字符串字面量(如
fetch("https://api.x.com"))也会被替换,但要注意引号类型(单/双/反引号)和转义,建议用完整 URL + 引号包裹方式匹配,例如:sub_filter '"https://api.x.com"' '"/api-proxy"'; - 不适用于二进制响应(图片、字体等)、HTTP/2 推送资源、或 Service Worker 缓存内容——这些不在响应体文本流中,sub_filter 无法触达
替代方案参考(当 sub_filter 不足时)
若需更可靠、结构化重写(如只改 HTML 属性、跳过注释/字符串、支持正则),可考虑:
- 使用
ngx_http_substitutions_filter_module(第三方模块,支持正则和多级替换) - 在应用层注入代理逻辑(如通过 webpack alias 或运行时环境变量)
- 用 Lua(OpenResty)做响应体解析与 DOM 级重写:
body_filter_by_lua_block{ ... },灵活但增加运维复杂度











