我要启动火山引擎rtc的StartVoiceChat
10 2026-03-20 23:21 2026-03-21 00:04
我要启动火山引擎rtc的StartVoiceChat,要求从配置文件中获取参数。使用node和docker-compose,网页上只有两个按钮以及启动成功与否的报错调试信息
下面给出一份最小可运行的“Node.js + Docker Compose”示例,满足:
-
读取你提供的 config.json(已放在项目根目录)
-
网页只有两个按钮:「启动」和「停止」
-
点击按钮后,前端拿到「成功/失败」以及火山返回的原始信息,方便调试
-
全部走本地一个容器,端口 3000
一、目录结构 . ├── docker-compose.yml ├── Dockerfile ├── package.json ├── server.js ├── config.json ← 你上传的那份 └── public └── index.html
二、关键代码
-
package.json
JSON
复制
{
"name": "volc-rtc-demo",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"axios": "^1.6.0",
"express": "^4.18.2",
"uuid": "^9.0.1"
}
}
-
server.js(Node 18+)
JavaScript
复制
import express from 'express';
import axios from 'axios';
import { readFileSync } from 'fs';
import crypto from 'crypto';
import { v4 as uuid } from 'uuid';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const cfg = JSON.parse(readFileSync('./config.json', 'utf8'));
const app = express();
app.use(express.json());
app.use(express.static('public'));
// 火山签名工具函数
function signReq(method, uri, query, headers, ak, sk, region, service) {
const algorithm = 'AWS4-HMAC-SHA256';
const now = new Date();
const dateStr = now.toISOString().replace(/[:\-]|\.\d{3}/g, '');
const dateYmd = dateStr.slice(0, 8);
const credentialScope = `${dateYmd}/${region}/${service}/request`;
// 1. CanonicalRequest
const headerKeys = Object.keys(headers).sort();
const signedHeaders = headerKeys.join(';');
const canonicalHeaders = headerKeys.map(k => `${k}:${headers[k]}\n`).join('');
const payloadHash = headers['x-content-sha256'] || 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
const canonicalReq = [
method.toUpperCase(),
uri,
query || '',
canonicalHeaders,
signedHeaders,
payloadHash
].join('\n');
// 2. StringToSign
const stringToSign = [
algorithm,
dateStr,
credentialScope,
crypto.createHash('sha256').update(canonicalReq).digest('hex')
].join('\n');
// 3. SigningKey
const kDate = crypto.createHmac('sha256', `AWS4${sk}`).update(dateYmd).digest();
const kRegion = crypto.createHmac('sha256', kDate).update(region).digest();
const kService = crypto.createHmac('sha256', kRegion).update(service).digest();
const signingKey = crypto.createHmac('sha256', kService).update('request').digest();
const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex');
headers.Authorization = `${algorithm} Credential=${ak}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
}
// 统一请求火山 OpenAPI
async function volcRequest(action, body) {
const host = cfg.ak_sk.API_HOST;
const region = cfg.ak_sk.REGION;
const service = cfg.ak_sk.SERVICE;
const ak = cfg.ak_sk.AK;
const sk = cfg.ak_sk.SK;
const query = `Action=${action}&Version=2022-06-01`;
const uri = '/';
const url = `https://${host}${uri}?${query}`;
const headers = {
'content-type': 'application/json',
'x-content-sha256': crypto.createHash('sha256').update(JSON.stringify(body)).digest('hex'),
host
};
signReq('POST', uri, query, headers, ak, sk, region, service);
return axios.post(url, body, { headers });
}
// 启动语音聊天
app.post('/api/start', async (req, res) => {
try {
const r = await volcRequest('StartVoiceChat', cfg.start_data);
res.json({ ok: true, data: r.data });
} catch (e) {
res.json({ ok: false, error: e.response?.data || e.message });
}
});
// 停止语音聊天
app.post('/api/stop', async (req, res) => {
try {
const r = await volcRequest('StopVoiceChat', cfg.stop_data);
res.json({ ok: true, data: r.data });
} catch (e) {
res.json({ ok: false, error: e.response?.data || e.message });
}
});
app.listen(3000, () => console.log('listen :3000'));
-
public/index.html
HTML
预览
复制
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>VolcRTC 快速调试</title>
<style>
body{font-family:Arial,Helvetica,sans-serif;text-align:center;margin-top:100px}
button{width:120px;height:40px;margin:10px;font-size:16px}
#log{width:600px;margin:30px auto;text-align:left;border:1px solid #ccc;padding:10px;height:200px;overflow:auto}
</style>
</head>
<body>
<h2>火山引擎 RTC 语音聊天</h2>
<button id="btnStart">启动</button>
<button id="btnStop">停止</button>
<div id="log"></div>
<script>
const log = (msg) => document.getElementById('log').innerHTML += `<div>${new Date().toLocaleTimeString()} ${msg}</div>`;
const post = async (url) => {
try {
const r = await fetch(url, {method:'POST'});
const j = await r.json();
if(j.ok) log(`✅ 成功:${JSON.stringify(j.data)}`);
else log(`❌ 失败:${JSON.stringify(j.error)}`);
} catch(e) {
log(`❌ 网络异常:${e.message}`);
}
};
document.getElementById('btnStart').onclick = () => post('/api/start');
document.getElementById('btnStop').onclick = () => post('/api/stop');
</script>
</body>
</html>
-
Dockerfile
dockerfile
复制
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
EXPOSE 3000
CMD ["npm","start"]
-
docker-compose.yml
yaml
复制
version: "3.9"
services:
web:
build: .
ports:
- "3000:3000"
volumes:
- ./config.json:/app/config.json:ro # 改配置无需重建镜像
三、运行
-
把上面 6 个文件放到同一目录,config.json 用你那份。
-
终端执行bash
-
复制
docker compose up --build -
浏览器打开 http://localhost:3000
点击「启动」/「停止」,下方灰色调试框会立刻给出火山返回的 JSON 或错误详情。
四、常见坑
-
若提示 “Unauthorized”:
-
确认 AK/SK 与控制台一致
-
检查本机时间(签名对时间敏感)
-
-
若提示 “AppId 不存在”:
把 config.json 里的 AppId 换成你在火山 RTC 控制台真实创建的 -
想改语音音色/ASR 模型:
直接改 config.json 里对应字段,保存后重启容器即可(因挂载了只读卷)。
目录结构给我再看一遍
编辑
复制
分享
项目根目录结构(完整再列一次):
plain
复制
.
├── docker-compose.yml
├── Dockerfile
├── package.json
├── server.js
├── config.json ← 你上传的那份
└── public
└── index.html
根目录起个什么名字
编辑
复制
分享
名字随意,只要一眼能认出这是“火山 RTC 一键 Demo”即可。下面给你几个直接可用的文件夹命名,挑一个顺眼就行:
-
volc-rtc-quickstart -
volc-rtc-docker-demo -
rtc-volcengine-node -
volc-rtc-oneclick
示例(选 1):
plain
复制
volc-rtc-quickstart/
├── docker-compose.yml
├── Dockerfile
├── package.json
├── server.js
├── config.json
└── public/
└── index.html
如何启动?是用docker-compose up -d吗?
是的,用
docker-compose up -d 启动,但因为你添加了新依赖 katex,需要先重新构建镜像。完整启动步骤
bash
复制
# 1. 进入项目目录
cd /path/to/your/project
# 2. 停止旧容器(如果正在运行)
docker-compose down
# 3. 重新构建并启动(关键!安装 katex 依赖)
docker-compose up -d --build
# 4. 查看日志确认启动成功
docker-compose logs -f
# 5. 测试访问
curl http://localhost:3000/health
常用命令速查
表格
| 命令 | 作用 |
|---|---|
docker-compose up -d |
后台启动(首次或配置变更后需加 --build) |
docker-compose up -d --build |
重新构建镜像并启动(安装新依赖时用) |
docker-compose down |
停止并删除容器 |
docker-compose logs -f |
实时查看日志 |
docker-compose ps |
查看运行状态 |
docker-compose restart |
重启服务(不改镜像) |
然后浏览器访问:
-
http://localhost:3000/→ 原有首页 -
http://localhost:3000/latex→ LaTeX 编辑器
如果报错
如果提示
katex 模块找不到,说明镜像没重建,强制重新构建:bash
复制
# 强制无缓存重建
docker-compose build --no-cache
docker-compose up -d
现在就可以运行
docker-compose up -d --build 启动了!
全部评论