当 HTTPS 页面加载 HTTP 资源时,就会产生混合内容(Mixed Content)。浏览器会阻止不安全的请求,导致页面功能异常。本文介绍混合内容的类型、排查方法和解决方案。

什么是混合内容

HTTPS 页面中通过 HTTP 加载的资源称为混合内容:

1
2
3
4
<!-- HTTPS 页面中的混合内容 -->
<script src="http://example.com/script.js"></script>
<img src="http://example.com/image.jpg">
<link rel="stylesheet" href="http://example.com/style.css">

混合内容类型

混合被动内容(Mixed Passive Content)

低风险资源,浏览器通常只显示警告:

  • <img> 图片
  • <audio> / <video> 媒体
  • <object> 子资源

混合主动内容(Mixed Active Content)

高风险资源,浏览器会直接阻止:

  • <script> 脚本
  • <link> 样式表
  • <iframe> 内嵌页面
  • XMLHttpRequest / Fetch 请求
  • <frame> / <object> 加载的页面

排查方法

浏览器控制台

打开开发者工具(F12),查看 Console 和 Security 面板:

1
2
3
Mixed Content: The page at 'https://example.com/' was loaded over HTTPS,
but requested an insecure script 'http://cdn.example.com/script.js'.
This request has been blocked.

curl 检查

1
curl -I https://example.com 2>&1 | grep -i "location\|http"

解决方案

1. 协议相对 URL

使用 // 代替 http://https://

1
2
3
4
5
<!-- 修改前 -->
<script src="http://cdn.example.com/script.js"></script>

<!-- 修改后 -->
<script src="//cdn.example.com/script.js"></script>

浏览器会自动使用当前页面的协议。

2. 强制 HTTPS

直接使用 HTTPS URL:

1
<script src="https://cdn.example.com/script.js"></script>

3. 服务器端重定向

配置服务器将 HTTP 重定向到 HTTPS:

Nginx:

1
2
3
4
5
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

4. Content-Security-Policy

使用 CSP 强制升级不安全请求:

1
add_header Content-Security-Policy "upgrade-insecure-requests";

这会自动将页面中所有 HTTP 请求升级为 HTTPS。

5. HSTS

启用 HSTS 告诉浏览器始终使用 HTTPS:

1
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

常见场景

第三方资源

许多第三方服务同时支持 HTTP 和 HTTPS:

1
2
3
4
5
<!-- Google Analytics -->
<script src="https://www.googletagmanager.com/gtag/js"></script>

<!-- 字体 -->
<link href="https://fonts.googleapis.com/css2" rel="stylesheet">

本地开发

开发环境使用自签名证书时,浏览器可能阻止混合内容。可以:

  1. 使用 mkcert 生成本地信任证书
  2. Chrome 访问 chrome://flags/#allow-insecure-localhost

API 请求

前端调用后端 API 时确保使用 HTTPS:

1
2
3
4
5
6
7
// 错误
fetch('http://api.example.com/data')

// 正确
fetch('https://api.example.com/data')
// 或使用相对路径
fetch('/api/data')

检查清单

检查项 方法
页面资源 浏览器控制台
API 请求 Network 面板
第三方服务 确认支持 HTTPS
重定向配置 curl -I 测试
CSP 策略 响应头检查

总结

混合内容会破坏 HTTPS 的安全性,浏览器会阻止主动混合内容。解决方案包括:

  1. 使用协议相对 URL 或直接 HTTPS
  2. 配置 CSP 的 upgrade-insecure-requests
  3. 启用 HSTS
  4. 确保所有第三方资源支持 HTTPS