Article
背景说明
在本地开发阶段,我需要接入 阿里云的 AI 实时对话功能。
该能力对运行环境有两个硬性要求:
- 页面必须运行在
localhost或 HTTPS 环境下 - 用户身份信息必须基于 域名 才能正常获取
这两个条件在生产环境中不存在问题,但在本地开发阶段却直接形成了冲突。
为什么不能直接使用 http + IP?
最初的访问方式是:
但阿里云 AI 实时对话 SDK 会直接拒绝初始化。
原因在于:
- WebRTC / Audio / Media 等能力
- 浏览器统一要求 Secure Context
- HTTP + IP 属于 不安全上下文
因此该方案不可行。
为什么又必须使用域名?
即使将前端服务改为:
仍然会遇到新的问题:
- 登录态丢失
- Cookie 无法正确读取
- 与后端鉴权逻辑不一致
这是因为:
- 用户身份与鉴权信息依赖域名上下文
localhost无法模拟真实业务域名环境
结论是:本地开发必须使用自定义域名访问。
初始方案:hosts + 自签 HTTPS
为了解决上述问题,我采用了一个看起来非常合理的方案:
- 修改 hosts:127.0.0.1 dev.example.com
- 为本地服务生成自签 SSL 证书
- 前端服务启用 HTTPS
- 通过 https://dev.example.com 访问页面
表面上看,这已经同时满足了 HTTPS 与域名访问的要求。
但真正的坑,才刚刚开始。
证书不可用:最核心的坑点
在页面中请求后端接口时,浏览器直接报错:
- ERR_CERT_AUTHORITY_INVALID
- TypeError: Failed to fetch
即便在浏览器地址栏中手动点击了“继续访问(不安全)”, 页面可以正常打开,但接口请求仍然全部失败。
这不是 HTTP 问题,而是 TLS 问题
真实发生的过程是:
- TCP 三次握手成功
- TLS 握手开始
- 浏览器接收到服务器证书
- 校验证书签发者(CA)
- 发现是自签证书
- CA 不在系统信任列表中
- TLS 握手失败,连接被主动中断
请求在进入 JavaScript 之前就已经失败。
为什么“地址栏能访问,接口却不行”?
浏览器地址栏的“继续访问”只是 UI 层面的临时放行。
fetch / xhr / WebSocket 不会继承这个信任,仍然会严格校验证书。
因此会出现页面能打开,但接口全部失败的现象。
根本原因总结
HTTPS 的信任建立在 CA 之上,而不是证书本身。
当时的环境是:
- 域名:hosts 绑定
- HTTPS:自签证书
- CA:不被系统信任
这是 TLS 设计层面的必然结果。
正确的本地 HTTPS 方案
正确的做法不是多签几张证书,而是引入 本地 CA。
信任结构应当是:
本地 CA(已被系统信任) ├── dev.example.com └── api.example.com
最终解决方案:mkcert
最终采用了 mkcert:
- 创建本地 CA
- 将 CA 安装进系统信任链
- 使用同一个 CA 签发前端与后端证书
- hosts 绑定域名
- 全程 HTTPS 访问
最终效果:
- 浏览器完全信任
- fetch / WebSocket 正常
- 阿里云 AI 实时对话 SDK 正常工作
- 本地环境行为与生产环境一致
总结
这次踩坑让我真正理解了几个事实:
- 本地开发并不等于可以绕过安全机制
- 自签证书 ≠ 被信任证书
- 浏览器只信任 CA,而不信任你手动点过的“继续访问”
- 本地接入第三方云能力时,应尽量模拟生产环境
本地 CA 不是优化项,而是刚需。