核心要点概括
当 HTTPS 页面尝试请求 HTTP 接口(如 Fetch、XHR、Axios 请求)时,浏览器会拦截并报错,这被称为 Mixed Content(混合内容) 问题。
- 根本原因:浏览器的安全策略。HTTPS 旨在提供加密和身份验证,如果在安全页面中加载不安全的 HTTP 资源(特别是脚本或 API 数据),会破坏整个页面的安全性,容易遭受中间人攻击(MITM)。
- 浏览器行为:默认完全阻止“主动混合内容”(如 API 请求、JS 文件),通常会在控制台报
Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure ...错误。 - 解决方案:最彻底的方法是将后端接口升级为 HTTPS;临时或特定场景下可使用 Nginx 反向代理或 CSP 头自动升级请求。
一文讲透 Mixed Content
1. 什么是 Mixed Content?
Mixed Content 发生在初始 HTML 通过安全的 HTTPS 连接加载,但随后该页面请求了不安全的 HTTP 资源(如图片、视频、样式表、脚本、API 接口)时。
2. 混合内容的分类
浏览器对不同类型的资源处理方式不同,主要分为两类:
-
被动混合内容 (Passive/Display Mixed Content)
- 内容:图片 (
<img>)、音频 (<audio>)、视频 (<video>)。 - 后果:风险较低。浏览器通常不会阻止加载,但会移除地址栏的“安全锁”图标,或显示“不安全”的警告。
- 内容:图片 (
-
主动混合内容 (Active/Script Mixed Content) —— 你的问题在这里
- 内容:API 请求 (XHR/Fetch) 、JavaScript (
<script>)、CSS (<link>)、Iframe、Flash。 - 后果:风险极高。攻击者可以拦截并篡改这些内容,从而完全控制页面。因此,现代浏览器(Chrome, Safari, Firefox 等)默认直接拦截,导致请求失败。
- 内容:API 请求 (XHR/Fetch) 、JavaScript (
3. 为什么必须拦截 HTTP 接口?
如果在 HTTPS 银行网页上,使用 HTTP 请求加载一段 JavaScript 或提交登录数据:
- 失去机密性:黑客可以嗅探 HTTP 数据包,窃取用户的 Token 或密码。
- 失去完整性:黑客可以修改 HTTP 返回的数据(例如将转账目标账号修改),而浏览器无法察觉。
- 误导用户:地址栏显示 HTTPS 锁图标,用户以为安全,但实际上页面已被不安全脚本控制。
4. 解决方案大全
以下按推荐程度从高到低排列:
方案一:全站 HTTPS(最佳实践)
将后端接口服务升级为 HTTPS。这是唯一的治本之策。
- 操作:为后端服务器(如 API 服务器)申请 SSL 证书(可以使用免费的 Let's Encrypt),并在 Nginx/Apache/Tomcat 中配置 443 端口。
- 优点:彻底解决安全问题,符合现代 Web 标准。
方案二:Nginx 反向代理(最常用)
如果后端代码太老旧无法改动,或者后端不在你控制范围内,可以通过前端部署的 Nginx 做“中转”。
-
原理:浏览器请求前端 Nginx (HTTPS) -> Nginx 转发给后端 (HTTP)。浏览器只和 Nginx 交互,看到的都是 HTTPS,因此不会报错。
-
Nginx 配置示例:
Nginx
server { listen 443 ssl; server_name www.yourdomain.com; # SSL 配置省略... # 前端页面 location / { root /var/www/html; index index.html; } # 代理后端接口 location /api/ { # 这里将请求转发给 HTTP 的后端 proxy_pass http://api.backend.com:8080/; # 传递必要的头信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
方案三:CSP header 自动升级(仅限资源支持 HTTPS 时)
如果你的后端其实已经支持 HTTPS,但你的前端代码里写死了大量的 http:// 链接,不想一个个改代码,可以使用 CSP (Content Security Policy)。
-
操作:在 Nginx 响应头或 HTML
<meta>标签中加入:HTML
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> -
效果:浏览器在发出请求前,会自动将页面内所有的
http://请求强制替换为https://。 -
局限:如果后端服务器真的只开了 80 端口(不支持 443/HTTPS),这个请求升级后会因为连接不上而失败。
方案四:相对协议(Protocol-relative URL)
在代码中尽量避免写死协议。
- 不要写:
http://api.example.com/data - 要写:
//api.example.com/data - 效果:浏览器会根据当前页面是 HTTP 还是 HTTPS,自动选择对应的协议前缀。
总结表格
| 方案 | 适用场景 | 难度 | 推荐指数 |
|---|---|---|---|
| 后端开启 HTTPS | 拥有后端控制权,生产环境 | 中 | ⭐⭐⭐⭐⭐ |
| Nginx 代理 | 无法修改后端,或前后端分离部署 | 中 | ⭐⭐⭐⭐⭐ |
| CSP 自动升级 | 代码写死 HTTP 但服务器支持 HTTPS | 低 | ⭐⭐⭐ |
| 本地开发特例 | 仅由开发者在本地调试时关闭浏览器安全限制 | 低 | ⭐ (仅限调试) |