From fcb7e009ebddee6765a08817d35e3ac6f98cfb89 Mon Sep 17 00:00:00 2001 From: cc <94575594@qq.com> Date: Mon, 23 Mar 2026 15:57:21 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20docs:=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=96=87=E6=A1=A3=20DEPLOY.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DEPLOY.md | 381 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 DEPLOY.md diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..bed2eb9 --- /dev/null +++ b/DEPLOY.md @@ -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 # 本文档 +```