CWFrame 项目部署文档 / CWFrame Project Deployment Guide
1. 核心架构设计
| 层级 | 技术选型 | 部署平台 |
|---|---|---|
| 前端 | Vue 3 | Vercel |
| 后端 | Node.js (Koa/Express) + Prisma | 腾讯云 Ubuntu |
| 数据库 | TiDB Cloud (MySQL 兼容) | AWS 日本区 |
| 安全/通信 | SSL 证书 + Nginx 反代 | 自有域名 tidenflow.life |
逻辑架构图
用户浏览器 --(HTTPS/域名)--> Vercel --(API 请求)--> 腾讯云 Nginx --(反代)--> Node.js 运行环境 --(跨海连接)--> TiDB Cloud流量生命周期 (Traffic Lifecycle):
DNS 层:腾讯云解析将 api 子域名导向服务器 IP。
入口层:Nginx 监听 443,利用 SSL 证书进行 TLS 卸载 (TLS Termination),将加密流量转化为内网 HTTP。
应用层:Node.js 接收请求,通过 Prisma 驱动跨越 2000+ 公里 调用 TiDB 日本集群。
持久层:TiDB Serverless 自动处理 SQL 请求并返回 84 个地图节点。2. 部署流程与关键操作
2.1 第一阶段:域名与 SSL 证书
操作步骤:
- 在腾讯云申请免费 SSL 证书,获取
.pem和.key文件 - 添加 DNS 解析记录:
- A 记录:将
api.tidenflow.life指向腾讯云服务器 IP - CNAME 记录:将主域名指向 Vercel 提供的地址
- TTL:600 秒
- A 记录:将
注意事项:
- 需在腾讯云安全组开放 443 端口(HTTPS)
2.2 第二阶段:后端与数据库
操作步骤:
- 在 TiDB Cloud 创建集群(Serverless)
- 获取连接字符串
DATABASE_URL,写入服务器.env文件 - 在 Ubuntu 安装 Nginx,配置反向代理:
- 监听 443 端口,挂载 SSL 证书
- 配置
proxy_pass http://127.0.0.1:3000;转发到 Node.js
- 在腾讯云安全组开放端口:80、443、22、3000
问题解决:
- 事务超时 (P2028):同步数据时跨海延迟超过 Prisma 默认 5 秒限制
- 解法:在
$transaction中添加timeout: 30000
- 解法:在
2.3 第三阶段:前端部署
操作步骤:
- 在 Vercel 控制台修改环境变量
VITE_API_BASE_URL - 执行 Redeploy 重新构建
问题解决:
- 混合内容报错 (Mixed Content):Vercel 强制 HTTPS,但后端是 HTTP IP
- 解法:API 地址从
http://82.157.x.x升级为https://api.tidenflow.life
- 解法:API 地址从
2.4 第四阶段:数据初始化
操作步骤:
- 执行
npm run sync:map同步脚本 - 将地图节点数据从 JSON 解析并存入 TiDB
问题解决:
- 地图加载失败:注册成功但登录后黑屏,报错
default map not found- 解法:运行同步脚本将节点数据 Upsert 到数据库
3. 经验总结
| 经验点 | 说明 |
|---|---|
| 链路闭环验证 | users 表有新数据说明网络和数据库已通,剩下是业务数据问题 |
| 安全组意识 | 部署 Web 应用,防火墙端口规则是第一优先级 |
| 环境变量 | Vercel 环境变量修改后必须 Redeploy 才生效 |
| 网络延迟 | 地理距离产生的延迟是出海项目必备考量因素 |
4. 关键技术解释
Nginx 的作用
- 门卫(监听端口):Node.js 躲在 3000 端口(内网),Nginx 站在 80/443 端口负责接待外部请求
- 翻译官(SSL 解密):Vercel 发来 HTTPS 加密请求,Nginx 用 SSL 证书解密后转为 HTTP 发给 Node.js
- 反向代理:将外部对
api.tidenflow.life的访问转发到服务器内部127.0.0.1:3000
DNS 记录类型
- A 记录:将域名指向 IP 地址
- CNAME 记录:将域名指向另一个域名
- TTL:解析记录在缓存中的生存时间
5. 部署最终状态
- 前端:Vercel (公网访问入口)
- 后端:腾讯云 Ubuntu + Nginx 反代
- 数据库:TiDB Cloud (AWS 日本区)
- 域名:
api.tidenflow.life(HTTPS)