React调用本地Flask API遇net::ERR_CERT_COMMON_NAME_INVALID错误求助
这是我的第一个完整全栈应用,我并非专业运维人员。
背景
网站testwebsite.com采用ReactJS前端,部署在Ubuntu 20.04系统的Caddy服务器上,同服务器运行Python Flask API。Flask监听0.0.0.0:3000,网站使用Caddy默认自签名HTTPS证书,Flask使用ZeroSSL生成的证书和密钥,通过Google Chrome访问网站。
当前问题
用户可正常通过HTTPS访问网站,但前端每5秒用fetch调用网站外部IP的Flask API(示例代码:const response = await fetch("https://123.123.123.123:3000/testing" ...)时,请求无法到达Flask服务器,控制台报错:GET https://123.123.123.123:3000/testing net::ERR_CERT_COMMON_NAME_INVALID。
已尝试的解决方法
- 在Flask服务器使用Caddy的证书和密钥
- 将Flask改为监听
127.0.0.1,fetch调用改为127.0.0.1:3000,出现连接拒绝错误 - 让API不使用SSL,用
http://调用,出现混合内容SSL错误 - 使用Cloudflare的证书,浏览器不信任
- 以adhoc模式运行Flask,出现CA机构不被信任的SSL错误
- 改用Apache服务器,未尝试Cloudflare证书,效果不佳
- 开启Flask的CORS,仍未解决核心问题
方案1:用Caddy反向代理Flask API(最推荐)
利用Caddy的HTTPS能力统一处理证书,不用给Flask单独配置SSL,还能避免跨域和证书问题,适合新手快速解决:
- 修改Caddy配置文件(通常路径为
/etc/caddy/Caddyfile),给testwebsite.com新增API路由,把请求转发到本地Flask的3000端口:
testwebsite.com { # 保留原有的前端静态文件配置(比如指向React构建后的dist目录) root * /path/to/react/build/folder file_server # 新增API反向代理规则,所有/api开头的请求转发到Flask reverse_proxy /api/* localhost:3000 }
- 修改前端fetch请求地址,改成同域名的API路径,不用再写IP和端口:
const response = await fetch("/api/testing" ...);
- 调整Flask监听地址,改为
127.0.0.1:3000(不用对外暴露,Caddy会负责转发),修改Flask启动代码:
app.run(host="127.0.0.1", port=3000)
- 重启Caddy服务:
sudo systemctl restart caddy
优势:Caddy自动管理可信HTTPS证书(可替换默认自签名为Let's Encrypt证书),前端和API同域名无跨域问题,无需给Flask配置SSL,部署逻辑更简单。
方案2:给Flask配置匹配域名的可信证书
如果坚持单独给Flask配SSL,需确保证书绑定的域名/IP和访问地址一致:
- 用ZeroSSL重新生成证书,把API的访问域名(比如
api.testwebsite.com)或服务器公网IP加入证书的SAN(Subject Alternative Name)字段,确保证书的通用名称和访问地址匹配 - 配置Flask使用新证书:
from flask import Flask app = Flask(__name__) if __name__ == "__main__": app.run(host="0.0.0.0", port=3000, ssl_context=("path/to/your-cert.crt", "path/to/your-key.key"))
- 前端改用域名调用API,比如
https://api.testwebsite.com:3000/testing,尽量避免直接用IP(IP证书易触发浏览器警告) - 开放服务器3000端口的防火墙规则
方案3:临时允许混合内容(仅测试用,生产环境禁用)
如果想临时测试HTTP协议的API,可在Chrome中临时解除混合内容限制:
访问网站后,点击地址栏的锁图标 → 站点设置 → 不安全内容 → 设置为"允许"
但此方法仅适合本地测试,生产环境下浏览器会强制阻止HTTPS页面中的HTTP请求,不可用。
内容的提问来源于stack exchange,提问作者mperic

