错误
了解 API 错误响应、WebSocket 关闭代码及其处理方式
REST API 错误格式 (HTTP)
当标准 HTTP 端点发生错误时,API 会返回具有以下结构的 JSON 响应:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "人类可读的错误描述",
"details": {
// 附加背景信息(视错误类型而定)
}
}
}
WebSocket 错误格式 (WSS)
WebSockets 处理错误的方式有所不同。错误可能发生在初始连接握手阶段,也可能发生在音频生成过程中的数据流传输期间。
- 致命错误: 连接因特定的关闭代码(例如 4290)而断开。
- 处理中途错误: 服务器在关闭前发送一个扁平的 JSON 错误帧:
{"error": "直播期间积分不足"}
状态码与关闭码
HTTP 状态码 (REST)
| 状态 | 含义 | 描述 |
|---|---|---|
200 |
好的 | 请求成功 |
400 |
无效请求 | 请求参数无效或请求格式错误 |
401 |
未经授权 | API 密钥缺失或无效 |
402 |
需付款 | 积分不足以完成该请求 |
403 |
禁止访问 | API 密钥没有执行此操作的权限 |
404 |
未找到 | 请求的资源不存在 |
409 |
冲突 | 请求与当前状态冲突(例如,并发 HTTP 请求) |
429 |
请求过多 | 超出速率限制 |
500 |
内部服务器错误 | 我们这边出了点问题 |
WebSocket 关闭代码 (WSS)
| 代码 | 类型 | 描述 |
|---|---|---|
1000 |
正常关闭 | 数据流已成功完成。 |
3011 |
生成错误 | 上游 API 音频生成失败。请重试请求。 |
4001 |
缺少认证信息 | 握手期间,Authorization 头部未提供 API 密钥。 |
4002 |
认证失败 | 密钥无效、账户未激活、初始额度不足或受 IP 限制。 |
4290 |
并发限制 | 您已有一个处于活动状态的 TTS WebSocket 连接。每个用户仅限建立 1 个连接。 |
常见错误场景
1. 未经授权 / 身份验证失败
HTTP: 401
WSS:4001 / 4002
由于 API 密钥缺失或无效,或者受到 IP 白名单限制,身份验证失败。
常见原因:
- 缺少 Authorization: Bearer 请求头
- API 密钥格式无效或密钥已被撤销
- 从不在您密钥白名单中的 IP 地址进行连接
2. 积分不足
HTTP: 402
WSS:流中 JSON
您的账户没有足够的点数来完成此请求。
- HTTP: 在生成音频前立即失败。
- WebSocket: 如果在数据流传输过程中信用额度耗尽,服务器会发送
{"error": "直播期间积分不足"}并正常关闭连接。在额度耗尽前生成的音频仍会进行传输。
3. 并发与速率限制
HTTP: 409 / 429
WSS:4290
为确保公平使用,Moknah 每次处理每个用户的单个请求。
- HTTP 409: 您的账户已有另一项请求正在处理中,请等待其完成。
- HTTP 429: 您超过了每分钟 60 次请求 (RPM) 的限制。
- WSS 4290: 您尝试在第一个 WebSocket 连接仍处于活动状态时打开第二个连接。
4. 无效请求 / 错误数据
HTTP: 400
WSS:流中 JSON
请求参数无效,或者您超出了文本分块限制。
- HTTP: 缺少必填字段(text、voice_id)。
- WebSocket: 发送超过 2,000 个字符的文本片段将导致
{"error": "数据块过大。每个数据块最多包含 2000 个字符。"}.
处理代码中的错误
import requests
import time
def generate_speech(text, voice_id, api_key):
url = "https://moknah.io/api/v1/tts/generate"
headers = {"Authorization": f"Bearer {api_key}"}
response = requests.post(url, json={"text": text, "voice_id": voice_id}, headers=headers)
if response.status_code == 200:
return response.content # 音频片段
elif response.status_code == 402:
raise Exception("积分不足")
elif response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 5))
time.sleep(retry_after)
return generate_speech(text, voice_id, api_key) # 重试
elif response.status_code == 409:
time.sleep(5)
return generate_speech(text, voice_id, api_key) # 重试
else:
raise Exception(f"API error: {response.status_code}")
async function generateSpeech(text, voiceId, apiKey) {
const response = await fetch("https://moknah.io/api/v1/tts/generate", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ text: text, voice_id: voiceId })
});
if (response.ok) return await response.blob();
if (response.status === 429) {
const retryAfter = response.headers.get("Retry-After") || 5;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return generateSpeech(text, voiceId, apiKey);
}
if (response.status === 409) {
await new Promise(r => setTimeout(r, 5000));
return generateSpeech(text, voiceId, apiKey);
}
const error = await response.json();
throw new Error(error.error?.message || "API Error");
}
const ws = new WebSocket('wss://moknah.io/api/v1/api/v1/tts/ws/', {
headers: { "Authorization": `Bearer ${apiKey}` }
});
// Handle Mid-Stream JSON Errors
ws.on('message', (data, isBinary) => {
if (!isBinary) {
const msg = JSON.parse(data.toString());
if (msg.error) {
console.error("Stream Error:", msg.error);
// e.g., "Insufficient credits during stream"
}
}
});
// Handle Fatal Close Codes
ws.on('close', (code, reason) => {
switch(code) {
case 1000:
console.log("Stream finished successfully.");
break;
case 4001:
case 4002:
console.error("Authentication failed. Check your API key.");
break;
case 4290:
console.error("Concurrency limit reached. Close other active streams.");
// Wait a few seconds before attempting to reconnect
setTimeout(reconnect, 5000);
break;
case 3011:
console.error("Upstream generation failed. Please try again.");
break;
default:
console.error(`Disconnected with code ${code}`);
}
});
最佳实践:指数退避
针对 429 (HTTP)、409 (HTTP) 和 4290 (WSS) 错误,请采用指数退避策略:依次等待 1 秒、2 秒、4 秒等。这既能避免 API 过载,又能确保在锁定解除后请求能够成功。
API 支持
如有关于 API 的问题或疑问,请联系我们: api@moknah.io.