340 行
7.2 KiB
Markdown
340 行
7.2 KiB
Markdown
# 腾讯云部署说明
|
||
|
||
本文档记录当前后端部署到腾讯云函数 SCF,并连接腾讯云数据库 MySQL 与 COS 的最小流程。
|
||
|
||
## 1. 数据库初始化
|
||
|
||
先确认 `server/.env` 或部署环境变量中已配置数据库:
|
||
|
||
```env
|
||
DB_HOST=
|
||
DB_PORT=3306
|
||
DB_USER=root
|
||
DB_PASSWORD=
|
||
DB_NAME=jw_beauty
|
||
```
|
||
|
||
本地直连公网数据库时,需要在腾讯云数据库的安全组/白名单中放行本机公网 IP。若本地无法直连,也可以临时通过支持 SOCKS5 的代理建立本地 TCP 隧道,再覆盖 `DB_HOST` 和 `DB_PORT` 执行初始化。
|
||
|
||
```bash
|
||
cd server
|
||
npm install
|
||
npm run db:init
|
||
```
|
||
|
||
初始化会创建业务表,并写入临时后台账号。生产环境首次登录后应立即更换默认密码。
|
||
|
||
## 2. SCF 函数配置
|
||
|
||
当前函数 `jw-beauty-api` 是腾讯云 HTTP 函数。HTTP 函数部署包根目录需要包含可执行的 `scf_bootstrap`,由它启动 HTTP 服务。
|
||
|
||
本项目的 HTTP 函数启动文件:
|
||
|
||
```text
|
||
scf_bootstrap
|
||
```
|
||
|
||
`scf_bootstrap` 会执行:
|
||
|
||
```bash
|
||
node scripts/local-server.js
|
||
```
|
||
|
||
HTTP 服务监听端口使用环境变量 `PORT`,建议配置为 `9000`。
|
||
|
||
如果以后改为普通事件函数,入口才使用:
|
||
|
||
```text
|
||
index.main_handler
|
||
```
|
||
|
||
触发器:
|
||
|
||
```text
|
||
HTTP 触发器或函数 URL
|
||
```
|
||
|
||
触发器需要透传:
|
||
|
||
```text
|
||
method
|
||
path
|
||
headers
|
||
queryStringParameters
|
||
body
|
||
```
|
||
|
||
## 3. 环境变量
|
||
|
||
参考模板:
|
||
|
||
```text
|
||
server/.env.production.example
|
||
```
|
||
|
||
生产必须配置:
|
||
|
||
```env
|
||
NODE_ENV=production
|
||
TENCENT_SECRET_ID=
|
||
TENCENT_SECRET_KEY=
|
||
TENCENT_REGION=ap-guangzhou
|
||
DB_HOST=
|
||
DB_PORT=3306
|
||
DB_USER=
|
||
DB_PASSWORD=
|
||
DB_NAME=jw_beauty
|
||
COS_BUCKET=jw-bucket-1426323813
|
||
COS_REGION=ap-guangzhou
|
||
WECHAT_APPID=
|
||
WECHAT_SECRET=
|
||
JWT_SECRET=
|
||
ADMIN_JWT_SECRET=
|
||
ADMIN_USERNAME=admin
|
||
ADMIN_PASSWORD=
|
||
```
|
||
|
||
不要提交真实 `.env`、密钥、数据库密码或微信密钥。
|
||
|
||
## 4. 数据库网络
|
||
|
||
SCF 与腾讯云数据库建议使用同地域、同 VPC 内网连接。
|
||
|
||
如果使用公网地址,需要确认:
|
||
|
||
- 数据库已开启公网访问。
|
||
- 安全组允许 SCF 出口或本机出口访问数据库端口。
|
||
- `DB_PORT` 与控制台展示端口一致。
|
||
|
||
## 5. COS 固件
|
||
|
||
固件文件先上传到 COS,然后在后台登记对象 key。
|
||
|
||
相关接口:
|
||
|
||
```http
|
||
GET /api/v1/admin/firmware
|
||
POST /api/v1/admin/firmware
|
||
POST /api/v1/admin/firmware/:firmware_id/status
|
||
GET /api/v1/firmware/latest
|
||
```
|
||
|
||
小程序调用 `GET /api/v1/firmware/latest` 时,后端会返回短期有效的 COS 签名下载 URL。
|
||
|
||
## 6. 前端 API 地址
|
||
|
||
SCF HTTP 地址确认后,更新:
|
||
|
||
```text
|
||
miniprogram/config/env.js
|
||
admin-console/src/config/env.js
|
||
```
|
||
|
||
把 `test` 或 `prod` 改为腾讯云函数 HTTPS 地址。
|
||
|
||
微信小程序正式联调还需要在微信公众平台配置 `request 合法域名`。
|
||
|
||
## 7. 管理后台 H5 部署到 COS
|
||
|
||
管理后台构建产物位于:
|
||
|
||
```text
|
||
admin-console/dist/build/h5
|
||
```
|
||
|
||
先确认 `admin-console/src/config/env.js` 已指向测试或生产 API,再执行:
|
||
|
||
```bash
|
||
cd admin-console
|
||
npm install
|
||
npm run build:h5
|
||
```
|
||
|
||
如需直接上传到 COS,可复用 `server/.env` 中的 COS 凭证:
|
||
|
||
```bash
|
||
cd admin-console
|
||
npm run deploy:cos
|
||
```
|
||
|
||
默认上传前缀:
|
||
|
||
```text
|
||
admin/
|
||
```
|
||
|
||
可通过环境变量覆盖:
|
||
|
||
```bash
|
||
ADMIN_COS_PREFIX=admin-test/ npm run deploy:cos
|
||
```
|
||
|
||
## 8. 后端 SCF 代码更新
|
||
|
||
常规后端代码更新流程如下。当前线上函数名为 `jw-beauty-api`,部署包上传到 COS:
|
||
|
||
```text
|
||
deploy/jw-beauty-api/hox-http-function.zip
|
||
```
|
||
|
||
### 8.1 拉取代码并检查
|
||
|
||
```bash
|
||
git status --short --branch
|
||
git pull --ff-only
|
||
```
|
||
|
||
如果 `server/` 有依赖变更,先同步依赖:
|
||
|
||
```bash
|
||
cd server
|
||
npm install
|
||
```
|
||
|
||
部署前至少做语法检查:
|
||
|
||
```bash
|
||
cd server
|
||
node -c src/app.js
|
||
node -c src/index.js
|
||
node -c src/lib/serverless.js
|
||
node -c scripts/local-server.js
|
||
```
|
||
|
||
如果只改了某个路由,也可以额外检查对应文件,例如:
|
||
|
||
```bash
|
||
node -c src/routes/subscription.js
|
||
```
|
||
|
||
### 8.2 打包后端代码
|
||
|
||
部署包必须以 `server/` 为根目录打包,并包含:
|
||
|
||
- `index.js`
|
||
- `package.json`
|
||
- `package-lock.json`
|
||
- `scripts/`
|
||
- `scf_bootstrap`
|
||
- `src/`
|
||
- `sql/`
|
||
- `node_modules/`
|
||
|
||
不要把 `server/.env` 打进部署包。
|
||
|
||
实际使用命令:
|
||
|
||
```bash
|
||
cd server
|
||
rm -f /tmp/hox-http-function.zip
|
||
zip -qry /tmp/hox-http-function.zip index.js package.json package-lock.json scripts scf_bootstrap src sql node_modules
|
||
```
|
||
|
||
### 8.3 上传部署包到 COS
|
||
|
||
上传复用 `server/.env` 中的腾讯云/COS 凭证。命令只读取本地环境变量,不要把真实密钥写入文档或提交到 Git。
|
||
|
||
```bash
|
||
cd server
|
||
set -a; source ./.env; set +a
|
||
node - <<'NODE'
|
||
const fs = require('fs')
|
||
const COS = require('cos-nodejs-sdk-v5')
|
||
const cos = new COS({
|
||
SecretId: process.env.TENCENT_SECRET_ID,
|
||
SecretKey: process.env.TENCENT_SECRET_KEY
|
||
})
|
||
|
||
cos.putObject({
|
||
Bucket: process.env.COS_BUCKET,
|
||
Region: process.env.COS_REGION || process.env.TENCENT_REGION || 'ap-guangzhou',
|
||
Key: 'deploy/jw-beauty-api/hox-http-function.zip',
|
||
Body: fs.createReadStream('/tmp/hox-http-function.zip')
|
||
}, err => {
|
||
if (err) {
|
||
console.error(err)
|
||
process.exit(1)
|
||
}
|
||
console.log('uploaded deploy/jw-beauty-api/hox-http-function.zip')
|
||
})
|
||
NODE
|
||
```
|
||
|
||
### 8.4 更新 SCF 函数代码
|
||
|
||
使用 `tccli scf UpdateFunctionCode` 指向刚上传的 COS 对象:
|
||
|
||
```bash
|
||
cd server
|
||
set -a; source ./.env; set +a
|
||
/Users/guoguo/.local/bin/tccli scf UpdateFunctionCode \
|
||
--region ap-guangzhou \
|
||
--FunctionName jw-beauty-api \
|
||
--CosBucketName "$COS_BUCKET" \
|
||
--CosObjectName /deploy/jw-beauty-api/hox-http-function.zip \
|
||
--CosBucketRegion "${COS_REGION:-ap-guangzhou}" \
|
||
--secretId "$TENCENT_SECRET_ID" \
|
||
--secretKey "$TENCENT_SECRET_KEY"
|
||
```
|
||
|
||
如果命令返回 `RequestId`,表示更新请求已提交成功。函数实例刷新通常需要等待几秒。
|
||
|
||
### 8.5 更新后快速验证
|
||
|
||
```bash
|
||
node - <<'NODE'
|
||
const base = 'https://api.vsai.net.cn'
|
||
|
||
async function print(label, res) {
|
||
const text = await res.text()
|
||
console.log(label, res.status, text.slice(0, 1000))
|
||
return text
|
||
}
|
||
|
||
;(async () => {
|
||
await print('health', await fetch(base + '/health'))
|
||
|
||
const loginText = await print('login', await fetch(base + '/api/v1/admin/login', {
|
||
method: 'POST',
|
||
headers: { 'content-type': 'application/json' },
|
||
body: JSON.stringify({ username: 'admin', password: 'admin' })
|
||
}))
|
||
|
||
const token = JSON.parse(loginText).data && JSON.parse(loginText).data.token
|
||
if (token) {
|
||
await print('settings', await fetch(base + '/api/v1/admin/settings', {
|
||
headers: { authorization: 'Bearer ' + token }
|
||
}))
|
||
await print('dashboard', await fetch(base + '/api/v1/admin/dashboard', {
|
||
headers: { authorization: 'Bearer ' + token }
|
||
}))
|
||
}
|
||
})().catch(err => {
|
||
console.error(err)
|
||
process.exit(1)
|
||
})
|
||
NODE
|
||
```
|
||
|
||
常见成功结果:
|
||
|
||
- `GET /health` 返回 `code: 0`
|
||
- `POST /api/v1/admin/login` 使用 `admin/admin` 返回 `code: 0`
|
||
- `GET /api/v1/admin/settings` 返回 `code: 0`
|
||
- `GET /api/v1/admin/dashboard` 返回 `code: 0`
|
||
|
||
## 9. 部署后验证
|
||
|
||
建议按顺序验证:
|
||
|
||
```http
|
||
GET /health
|
||
POST /api/v1/admin/login
|
||
GET /api/v1/admin/dashboard
|
||
POST /api/v1/admin/devices
|
||
GET /api/v1/admin/devices
|
||
GET /api/v1/admin/firmware
|
||
```
|
||
|
||
再进入小程序验证:登录、扫码绑定、BLE 连接、绑定确认、普通模式护理、护理记录同步。
|