HTTPS页面请求HTTP接口失败?一文讲透Mixed Content

0 阅读4分钟

核心要点概括

当 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 等)默认直接拦截,导致请求失败。

3. 为什么必须拦截 HTTP 接口?

如果在 HTTPS 银行网页上,使用 HTTP 请求加载一段 JavaScript 或提交登录数据:

  1. 失去机密性:黑客可以嗅探 HTTP 数据包,窃取用户的 Token 或密码。
  2. 失去完整性:黑客可以修改 HTTP 返回的数据(例如将转账目标账号修改),而浏览器无法察觉。
  3. 误导用户:地址栏显示 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⭐⭐⭐
本地开发特例仅由开发者在本地调试时关闭浏览器安全限制⭐ (仅限调试)