📝 docs: 添加部署文档 DEPLOY.md
This commit is contained in:
parent
812d0557f7
commit
fcb7e009eb
|
|
@ -0,0 +1,381 @@
|
||||||
|
# AI 英语学习辅助平台 — 线上部署操作流程
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
|
||||||
|
- **项目名称**:AI 英语学习辅助平台
|
||||||
|
- **技术栈**:Vue 3 + Vite + Vue Router(History 模式)
|
||||||
|
- **构建产物**:纯静态文件(HTML / CSS / JS),可部署到任意静态托管服务
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、部署前准备
|
||||||
|
|
||||||
|
### 1.1 环境要求
|
||||||
|
|
||||||
|
| 工具 | 版本要求 |
|
||||||
|
|------|----------|
|
||||||
|
| Node.js | >= 18.x(推荐 20.x LTS) |
|
||||||
|
| npm | >= 9.x |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node -v
|
||||||
|
npm -v
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd AI_Demo
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、关键配置说明
|
||||||
|
|
||||||
|
### 2.1 API 配置(必须在部署前确认)
|
||||||
|
|
||||||
|
项目所有 API 密钥集中在 `src/config/index.js`,部署前请确认以下配置项均已填写正确:
|
||||||
|
|
||||||
|
| 配置项 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| `GRS_API_KEY` | GRS AI 接口密钥(作文批改 / 试题分析) |
|
||||||
|
| `DOUBAO_APP_ID` | 豆包语音 App ID |
|
||||||
|
| `DOUBAO_ACCESS_TOKEN` | 豆包语音访问令牌 |
|
||||||
|
| `DOUBAO_RESOURCE_ID` | 豆包 TTS 资源 ID |
|
||||||
|
| `DOUBAO_ASR_RESOURCE_ID` | 豆包 ASR 资源 ID |
|
||||||
|
| `ARK_API_KEY` | 火山引擎 Ark 大模型密钥 |
|
||||||
|
| `ARK_MODEL` | Ark 模型名称(如 doubao-pro-4k) |
|
||||||
|
|
||||||
|
### 2.2 跨域响应头要求(重要)
|
||||||
|
|
||||||
|
项目使用了 `@ffmpeg/ffmpeg`(WebAssembly),需要服务器返回以下响应头,否则视频讲解功能将无法运行:
|
||||||
|
|
||||||
|
```
|
||||||
|
Cross-Origin-Opener-Policy: same-origin
|
||||||
|
Cross-Origin-Embedder-Policy: require-corp
|
||||||
|
```
|
||||||
|
|
||||||
|
> 各部署平台的配置方式见下方对应章节。
|
||||||
|
|
||||||
|
### 2.3 API 代理配置(重要)
|
||||||
|
|
||||||
|
项目在开发环境通过 Vite 代理转发以下 API 请求,**生产环境必须在服务器/网关层配置对应的反向代理**:
|
||||||
|
|
||||||
|
| 前端请求路径前缀 | 代理目标 | 用途 |
|
||||||
|
|-----------------|----------|------|
|
||||||
|
| `/tts-api` | `https://openspeech.bytedance.com` | 豆包 TTS 语音合成 |
|
||||||
|
| `/ark-api` | `https://ark.cn-beijing.volces.com` | 火山引擎 Ark 大模型 |
|
||||||
|
| `/dashscope-api` | `https://dashscope.aliyuncs.com` | 阿里云百炼 |
|
||||||
|
| `/asr-ws` | `wss://openspeech.bytedance.com` | 豆包 ASR WebSocket |
|
||||||
|
|
||||||
|
> **ASR WebSocket 特殊说明**:`/asr-ws` 代理需要在代理层注入以下鉴权 Header(浏览器原生 WebSocket 不支持自定义 Header):
|
||||||
|
> - `X-Api-App-Key`
|
||||||
|
> - `X-Api-Access-Key`
|
||||||
|
> - `X-Api-Resource-Id`
|
||||||
|
> - `X-Api-Connect-Id`(每次连接随机 UUID)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、构建生产包
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
构建完成后,产物位于 `dist/` 目录,包含:
|
||||||
|
|
||||||
|
```
|
||||||
|
dist/
|
||||||
|
├── index.html
|
||||||
|
├── favicon.svg
|
||||||
|
└── assets/
|
||||||
|
├── *.js
|
||||||
|
└── *.css
|
||||||
|
```
|
||||||
|
|
||||||
|
可在本地预览构建结果:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、部署方案
|
||||||
|
|
||||||
|
### 方案 A:Nginx 部署(推荐,自有服务器)
|
||||||
|
|
||||||
|
#### 4.A.1 上传文件
|
||||||
|
|
||||||
|
将 `dist/` 目录内容上传到服务器,例如 `/var/www/ai-demo/`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp -r dist/* user@your-server:/var/www/ai-demo/
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.A.2 Nginx 配置
|
||||||
|
|
||||||
|
创建或修改 Nginx 站点配置文件(如 `/etc/nginx/sites-available/ai-demo.conf`):
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name your-domain.com; # 替换为你的域名或 IP
|
||||||
|
|
||||||
|
root /var/www/ai-demo;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# 跨域响应头(FFmpeg WASM 必需)
|
||||||
|
add_header Cross-Origin-Opener-Policy "same-origin" always;
|
||||||
|
add_header Cross-Origin-Embedder-Policy "require-corp" always;
|
||||||
|
|
||||||
|
# Vue Router History 模式:所有路由回退到 index.html
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 代理:豆包 TTS
|
||||||
|
location /tts-api/ {
|
||||||
|
proxy_pass https://openspeech.bytedance.com/;
|
||||||
|
proxy_ssl_server_name on;
|
||||||
|
proxy_set_header Host openspeech.bytedance.com;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 代理:火山引擎 Ark
|
||||||
|
location /ark-api/ {
|
||||||
|
proxy_pass https://ark.cn-beijing.volces.com/;
|
||||||
|
proxy_ssl_server_name on;
|
||||||
|
proxy_set_header Host ark.cn-beijing.volces.com;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 代理:阿里云百炼
|
||||||
|
location /dashscope-api/ {
|
||||||
|
proxy_pass https://dashscope.aliyuncs.com/;
|
||||||
|
proxy_ssl_server_name on;
|
||||||
|
proxy_set_header Host dashscope.aliyuncs.com;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 代理:豆包 ASR WebSocket(需注入鉴权 Header)
|
||||||
|
location /asr-ws/ {
|
||||||
|
proxy_pass https://openspeech.bytedance.com/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host openspeech.bytedance.com;
|
||||||
|
proxy_ssl_server_name on;
|
||||||
|
# 注入豆包 ASR 鉴权 Header(替换为实际值)
|
||||||
|
proxy_set_header X-Api-App-Key "YOUR_DOUBAO_APP_ID";
|
||||||
|
proxy_set_header X-Api-Access-Key "YOUR_DOUBAO_ACCESS_TOKEN";
|
||||||
|
proxy_set_header X-Api-Resource-Id "volc.bigasr.sauc.duration";
|
||||||
|
}
|
||||||
|
|
||||||
|
# 静态资源缓存
|
||||||
|
location /assets/ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
add_header Cross-Origin-Opener-Policy "same-origin" always;
|
||||||
|
add_header Cross-Origin-Embedder-Policy "require-corp" always;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.A.3 启用配置并重启 Nginx
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 启用站点(Ubuntu/Debian)
|
||||||
|
ln -s /etc/nginx/sites-available/ai-demo.conf /etc/nginx/sites-enabled/
|
||||||
|
|
||||||
|
# 检查配置语法
|
||||||
|
nginx -t
|
||||||
|
|
||||||
|
# 重载 Nginx
|
||||||
|
systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.A.4 配置 HTTPS(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 使用 Certbot 申请免费 SSL 证书
|
||||||
|
apt install certbot python3-certbot-nginx
|
||||||
|
certbot --nginx -d your-domain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 方案 B:Node.js + Express 静态服务器
|
||||||
|
|
||||||
|
适用于需要在 Node.js 环境中自定义响应头的场景。
|
||||||
|
|
||||||
|
#### 4.B.1 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install express http-proxy-middleware
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.B.2 创建服务器文件 `server.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
import express from 'express'
|
||||||
|
import { createProxyMiddleware } from 'http-proxy-middleware'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
import path from 'path'
|
||||||
|
import crypto from 'crypto'
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
const app = express()
|
||||||
|
const PORT = process.env.PORT || 3000
|
||||||
|
|
||||||
|
// 全局注入 COOP/COEP 响应头(FFmpeg WASM 必需)
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
|
||||||
|
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
// API 代理
|
||||||
|
app.use('/tts-api', createProxyMiddleware({
|
||||||
|
target: 'https://openspeech.bytedance.com',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: { '^/tts-api': '' }
|
||||||
|
}))
|
||||||
|
|
||||||
|
app.use('/ark-api', createProxyMiddleware({
|
||||||
|
target: 'https://ark.cn-beijing.volces.com',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: { '^/ark-api': '' }
|
||||||
|
}))
|
||||||
|
|
||||||
|
app.use('/dashscope-api', createProxyMiddleware({
|
||||||
|
target: 'https://dashscope.aliyuncs.com',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: { '^/dashscope-api': '' }
|
||||||
|
}))
|
||||||
|
|
||||||
|
app.use('/asr-ws', createProxyMiddleware({
|
||||||
|
target: 'wss://openspeech.bytedance.com',
|
||||||
|
changeOrigin: true,
|
||||||
|
ws: true,
|
||||||
|
pathRewrite: { '^/asr-ws': '' },
|
||||||
|
on: {
|
||||||
|
proxyReqWs: (proxyReq) => {
|
||||||
|
proxyReq.setHeader('X-Api-App-Key', process.env.DOUBAO_APP_ID)
|
||||||
|
proxyReq.setHeader('X-Api-Access-Key', process.env.DOUBAO_ACCESS_TOKEN)
|
||||||
|
proxyReq.setHeader('X-Api-Resource-Id', 'volc.bigasr.sauc.duration')
|
||||||
|
proxyReq.setHeader('X-Api-Connect-Id', crypto.randomUUID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 静态文件服务
|
||||||
|
app.use(express.static(path.join(__dirname, 'dist')))
|
||||||
|
|
||||||
|
// Vue Router History 模式回退
|
||||||
|
app.get('*', (req, res) => {
|
||||||
|
res.sendFile(path.join(__dirname, 'dist', 'index.html'))
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`Server running at http://localhost:${PORT}`)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.B.3 启动服务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DOUBAO_APP_ID=xxx DOUBAO_ACCESS_TOKEN=xxx node server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 方案 C:EdgeOne Pages / Vercel / Netlify(纯静态托管)
|
||||||
|
|
||||||
|
> **注意**:此类平台**不支持服务端代理**,`/tts-api`、`/ark-api`、`/dashscope-api`、`/asr-ws` 等接口将因跨域或缺少鉴权 Header 而失败。
|
||||||
|
> 建议仅用于演示或配合独立后端服务使用。
|
||||||
|
|
||||||
|
#### 部署步骤(以 Vercel 为例)
|
||||||
|
|
||||||
|
1. 将项目推送到 GitHub
|
||||||
|
2. 在 Vercel 控制台导入仓库
|
||||||
|
3. 构建命令:`npm run build`,输出目录:`dist`
|
||||||
|
4. 创建 `vercel.json` 配置 History 模式路由回退和响应头:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"source": "/(.*)",
|
||||||
|
"headers": [
|
||||||
|
{ "key": "Cross-Origin-Opener-Policy", "value": "same-origin" },
|
||||||
|
{ "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、部署后验证清单
|
||||||
|
|
||||||
|
| 验证项 | 检查方法 |
|
||||||
|
|--------|----------|
|
||||||
|
| 页面正常加载 | 访问首页,确认 7 个功能卡片显示正常 |
|
||||||
|
| 路由刷新不 404 | 直接访问 `/pronunciation`、`/speaking` 等子路由 |
|
||||||
|
| COOP/COEP 响应头 | 浏览器 DevTools → Network → 查看 index.html 响应头 |
|
||||||
|
| TTS 语音合成 | 进入发音练习页,测试语音播放 |
|
||||||
|
| ASR 语音识别 | 进入口语对话页,测试麦克风录音识别 |
|
||||||
|
| 作文批改 | 进入作文批改页,提交一段英文作文 |
|
||||||
|
| 视频讲解(FFmpeg) | 进入视频讲解页,上传视频文件测试 |
|
||||||
|
| HTTPS 证书 | 确认浏览器地址栏显示锁形图标 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、常见问题排查
|
||||||
|
|
||||||
|
### Q1:视频讲解页面报错 `SharedArrayBuffer is not defined`
|
||||||
|
|
||||||
|
**原因**:服务器未返回 `Cross-Origin-Opener-Policy: same-origin` 和 `Cross-Origin-Embedder-Policy: require-corp` 响应头。
|
||||||
|
**解决**:参考第二节 2.2,在 Nginx 或 Node.js 服务器中添加对应响应头。
|
||||||
|
|
||||||
|
### Q2:刷新页面出现 404
|
||||||
|
|
||||||
|
**原因**:Vue Router 使用 History 模式,服务器未配置路由回退。
|
||||||
|
**解决**:Nginx 添加 `try_files $uri $uri/ /index.html;`,Node.js 添加通配路由返回 `index.html`。
|
||||||
|
|
||||||
|
### Q3:API 请求跨域报错(CORS)
|
||||||
|
|
||||||
|
**原因**:生产环境未配置反向代理,浏览器直接请求第三方 API 被跨域拦截。
|
||||||
|
**解决**:参考第二节 2.3,在 Nginx 或 Node.js 中配置对应代理规则。
|
||||||
|
|
||||||
|
### Q4:ASR 语音识别 WebSocket 连接失败
|
||||||
|
|
||||||
|
**原因**:代理未注入豆包 ASR 鉴权 Header,或 WebSocket 升级配置缺失。
|
||||||
|
**解决**:确认 Nginx 配置中包含 `proxy_set_header Upgrade $http_upgrade;` 及三个 `X-Api-*` Header。
|
||||||
|
|
||||||
|
### Q5:构建时内存不足
|
||||||
|
|
||||||
|
**原因**:项目包含 FFmpeg WASM,构建产物较大。
|
||||||
|
**解决**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 增大 Node.js 内存限制
|
||||||
|
NODE_OPTIONS=--max-old-space-size=4096 npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、目录结构参考
|
||||||
|
|
||||||
|
```
|
||||||
|
AI_Demo/
|
||||||
|
├── dist/ # 构建产物(部署此目录)
|
||||||
|
├── src/
|
||||||
|
│ ├── config/index.js # API 密钥配置(部署前确认)
|
||||||
|
│ ├── router/index.js # 路由定义
|
||||||
|
│ └── views/ # 页面组件
|
||||||
|
├── vite.config.js # 开发代理配置(生产环境需在服务器复现)
|
||||||
|
├── package.json
|
||||||
|
└── DEPLOY.md # 本文档
|
||||||
|
```
|
||||||
Loading…
Reference in New Issue