根本原因是https页面中硬编码的http外链被浏览器混合内容策略拦截;必须将所有等标签改为https://或协议相对路径//cdn.example.com/xxx,nginx 301无法修复html内链接,sub_filter仅可临时替换html响应体,hsts可防止用户发起http请求。

全站启用 HTTPS 后,静态外链(比如第三方 CDN 图片、字体、JS/CSS 链接)加载失败,根本原因不是 301 配置本身出错,而是这些外链仍用 http:// 协议,被现代浏览器主动阻止(Mixed Content)。Nginx 的 301 重定向只管服务器返回的响应地址,不改写 HTML 或响应体里的链接。要让外链正常加载,得从协议一致性入手。
确保页面资源全部走 HTTPS
浏览器拦截的是“HTTPS 页面里加载 HTTP 资源”,所以重点不是跳转逻辑,而是源头——网页中所有 <img src="http://...?x-oss-process=image/resize,p_40">、<link href="http://..."> 这类硬编码必须改成 https:// 或协议相对路径(//cdn.example.com/xxx)。否则无论 Nginx 怎么跳,浏览器在解析 HTML 时就直接屏蔽了。
- 检查模板、CMS 设置、富文本编辑器输出,批量替换
http://cdn.为https://cdn. - 对无法修改源码的旧页面,可临时用 Nginx 的
sub_filter替换响应体内容(仅限 text/html):sub_filter 'http://cdn.example.com/' 'https://cdn.example.com/';<br>sub_filter_once off;
注意:需开启sub_filter模块,且不适用于压缩后的响应(要关 gzip 或用gunzip on)
配置 HSTS 防止降级请求
即使你已强制跳转 HTTPS,用户如果手动输 http:// 或点击旧书签,仍会先发一次 HTTP 请求。若此时页面里有 http 外链,就会触发混合内容警告。启用 HSTS 可让浏览器记住“这个域名只走 HTTPS”,后续自动把所有 http:// 请求升为 https://,从源头避免混合内容发生:
- 在 HTTPS server 块中加入:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - 注意:
preload需提交到 HSTS Preload List 才生效;上线前先测试不含preload的版本 - HSTS 不影响外链本身协议,但能减少用户发起 HTTP 请求的机会,间接降低混合内容出现概率
验证外链是否真正支持 HTTPS
有些老外链看似是 HTTPS,实则证书过期、域名不匹配或服务端不支持 TLS 1.2+,也会导致加载失败。不能只看 URL 前缀:
- 用
curl -I https://cdn.example.com/widget.js检查返回状态码和证书信息 - 打开浏览器开发者工具 → Network 标签页,筛选
blocked或mixed-content,点开具体请求看详细错误(如 “net::ERR_CERT_DATE_INVALID”) - 对不支持 HTTPS 的第三方资源,联系对方升级,或考虑自建代理(反向代理该资源并加 SSL),但需注意版权与合规风险
避免 CDN 层面的协议冲突
如果你用了 Cloudflare、腾讯云 CDN 等,它们可能自带“强制 HTTPS”开关。若 CDN 开启了该功能,又在源站 Nginx 也配了 301,容易造成双重跳转,甚至因中间环节未透传 $request_uri 导致参数丢失,间接影响带参外链(如 https://cdn.com/ads?site=http://old.com):
- CDN 控制台关闭“自动 HTTPS 重定向”,由源站 Nginx 统一处理
- 确保 CDN 回源协议设为 HTTPS(尤其当源站只监听 443 时)
- 检查 CDN 是否缓存了含 http 外链的旧 HTML 页面——清除对应缓存或设置缓存键包含协议头











