Nginx 的 sub_filter 指令可动态将 HTML 响应中的 HTTP 链接替换为 HTTPS 以解决混合内容问题,但需满足:禁用压缩、匹配 MIME 类型、设置 sub_filter_once off,并精确配置替换规则。

使用 Nginx 的 sub_filter 指令可以在反向代理响应时,动态将 HTML 内容中的 HTTP 链接替换为 HTTPS,从而避免混合内容(Mixed Content)警告。关键在于:它只作用于响应体(response body),且默认不处理压缩内容、不递归匹配、需配合 sub_filter_once off 和正确 MIME 类型才能生效。
确保 sub_filter 生效的基本前提
sub_filter 不是万能开关,必须满足以下条件才真正起作用:
- 后端返回的响应头中
Content-Encoding必须为空(即未启用 gzip / brotli 压缩),否则 Nginx 不会解析原始 HTML;可临时在 proxy 配置中加proxy_set_header Accept-Encoding "";禁用压缩请求,或在 Nginx 中配置gunzip on;解压后再过滤(需编译含 gunzip 模块) - 响应的
Content-Type必须匹配sub_filter_types所设类型,默认仅text/html,若页面返回application/xhtml+xml或无类型,需显式添加 -
sub_filter默认只替换第一个匹配项,如需全局替换所有 HTTP 资源链接,必须设置sub_filter_once off; - 替换目标需严格匹配原始字符串,例如
http://cdn.example.com不会匹配https://cdn.example.com,也不匹配带端口的http://cdn.example.com:8080
典型配置示例(修正常见第三方 HTTP 资源)
以下配置将页面中所有绝对 HTTP 协议引用(含 script、img、link、iframe 等标签内)自动升级为 HTTPS:
location / {
proxy_pass https://origin-server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
<pre class="brush:php;toolbar:false;"># 关键:禁用后端压缩,确保拿到明文 HTML
proxy_set_header Accept-Encoding "";
# 启用 sub_filter,并扩展支持的 MIME 类型
sub_filter_types text/html text/xml text/plain application/xhtml+xml;
sub_filter_once off;
# 替换常见 HTTP 引用(注意顺序:先换带 www 的,再换裸域名,避免重复替换)
sub_filter 'http://www.google-analytics.com' 'https://www.google-analytics.com';
sub_filter 'http://cdn.jsdelivr.net' 'https://cdn.jsdelivr.net';
sub_filter 'http://fonts.googleapis.com' 'https://fonts.googleapis.com';
sub_filter 'http://ajax.googleapis.com' 'https://ajax.googleapis.com';
# 通用替换(谨慎使用!可能误伤 data URL 或注释)
sub_filter 'src="http://' 'src="https://';
sub_filter 'href="http://' 'href="https://';
sub_filter 'url(http://' 'url(https://';}
注意事项与常见陷阱
实际部署中容易忽略但影响极大的细节:
-
不要盲目替换整个
http://—— 例如http://localhost:3000/api若被替成https://localhost:3000/api,前端可能因证书无效或端口不可达而失败;建议按具体域名精确替换 -
JS 文件内硬编码的 HTTP 链接无法被 sub_filter 处理 —— 因为 JS 的
Content-Type通常是application/javascript,不在默认sub_filter_types中;如需处理,需显式加入并确认 JS 未压缩 -
相对协议 URL(
//cdn.example.com)无需替换,浏览器会自动继承当前页面协议,更安全可靠,建议推动前端优先采用此写法 -
sub_filter 不支持正则表达式,无法写成
sub_filter ~* 'http://([^"]+)';;如需复杂匹配,需改用ngx_http_substitutions_filter_module(第三方模块)或应用层改造
替代方案与长期建议
sub_filter 是应急手段,非架构级解法:
- 对新项目,强制前端使用
//协议相对路径或https://绝对路径,从源头规避问题 - 启用
Content-Security-Policy: upgrade-insecure-requests响应头,现代浏览器会自动将页面内所有 HTTP 请求升为 HTTPS(但不修改 DOM,仅拦截重发,部分老资源仍可能加载失败) - 使用 Service Worker 拦截 fetch 请求并重写协议(适用于 PWA 场景,但不兼容所有浏览器和环境)
- 在上游应用中统一注入
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

















