错误处理
了解 OpenHub API 的错误码和处理方法。
错误响应格式
所有错误响应遵循统一格式:
json
{
"success": false,
"data": null,
"error": {
"code": "ERROR_CODE",
"message": "错误描述"
}
}HTTP 状态码
| 状态码 | 说明 |
|---|---|
| 200 | 请求成功 |
| 400 | 请求参数错误 |
| 401 | 未认证或认证失败 |
| 403 | 权限不足 |
| 404 | 资源不存在 |
| 429 | 请求频率超限 |
| 500 | 服务器内部错误 |
| 503 | 服务暂时不可用 |
错误码列表
认证错误
| 错误码 | HTTP 状态码 | 说明 | 解决方法 |
|---|---|---|---|
UNAUTHORIZED | 401 | 未提供 API Key | 检查 Authorization header |
INVALID_API_KEY | 401 | API Key 无效 | 检查 API Key 是否正确 |
API_KEY_EXPIRED | 401 | API Key 已过期 | 重新生成 API Key |
FORBIDDEN | 403 | 权限不足 | 检查 API Key 权限设置 |
请求错误
| 错误码 | HTTP 状态码 | 说明 | 解决方法 |
|---|---|---|---|
INVALID_REQUEST | 400 | 请求格式错误 | 检查请求参数 |
MISSING_PARAMETER | 400 | 缺少必填参数 | 补充必填参数 |
INVALID_PARAMETER | 400 | 参数值无效 | 检查参数值范围 |
MODEL_NOT_FOUND | 404 | 模型不存在 | 使用正确的模型名称 |
资源错误
| 错误码 | HTTP 状态码 | 说明 | 解决方法 |
|---|---|---|---|
INSUFFICIENT_BALANCE | 402 | 余额不足 | 充值或升级套餐 |
QUOTA_EXCEEDED | 429 | 配额超限 | 等待配额重置或升级套餐 |
RATE_LIMIT_EXCEEDED | 429 | 请求频率超限 | 降低请求频率 |
内容错误
| 错误码 | HTTP 状态码 | 说明 | 解决方法 |
|---|---|---|---|
CONTENT_VIOLATION | 400 | 内容违规 | 修改请求内容 |
CONTENT_TOO_LONG | 400 | 内容过长 | 减少输入长度 |
服务错误
| 错误码 | HTTP 状态码 | 说明 | 解决方法 |
|---|---|---|---|
INTERNAL_ERROR | 500 | 服务器内部错误 | 重试或联系支持 |
SERVICE_UNAVAILABLE | 503 | 服务暂时不可用 | 稍后重试 |
TIMEOUT | 504 | 请求超时 | 重试或减少输入长度 |
错误处理示例
Python
python
from openai import OpenAI, APIError, RateLimitError, AuthenticationError
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.myopenhub.com/v1"
)
try:
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Hello"}]
)
except AuthenticationError as e:
print(f"认证错误: {e}")
# 检查 API Key
except RateLimitError as e:
print(f"请求频率超限: {e}")
# 等待后重试
except APIError as e:
print(f"API 错误: {e}")
# 处理其他错误Node.js
javascript
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'YOUR_API_KEY',
baseURL: 'https://api.myopenhub.com/v1'
});
try {
const response = await client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
});
} catch (error) {
if (error.status === 401) {
console.error('认证错误:', error.message);
// 检查 API Key
} else if (error.status === 429) {
console.error('请求频率超限:', error.message);
// 等待后重试
} else if (error.status === 402) {
console.error('余额不足:', error.message);
// 提示用户充值
} else {
console.error('API 错误:', error.message);
}
}重试策略
指数退避
javascript
async function callWithRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
// 不可重试的错误
if (error.status === 401 || error.status === 400) {
throw error;
}
// 最后一次重试失败
if (i === maxRetries - 1) {
throw error;
}
// 指数退避
const delay = Math.min(1000 * Math.pow(2, i), 10000);
await sleep(delay);
}
}
}
// 使用
const response = await callWithRetry(() =>
client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
})
);带抖动的退避
javascript
function getRetryDelay(attempt, baseDelay = 1000, maxDelay = 10000) {
const exponentialDelay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
const jitter = Math.random() * 1000;
return exponentialDelay + jitter;
}
async function callWithRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1 || !isRetryable(error)) {
throw error;
}
await sleep(getRetryDelay(i));
}
}
}
function isRetryable(error) {
// 5xx 错误和 429 可重试
return error.status >= 500 || error.status === 429;
}速率限制
限制说明
不同套餐有不同的速率限制:
| 套餐 | 每分钟请求数 | 每天请求数 | 并发数 |
|---|---|---|---|
| 免费版 | 60 | 1000 | 5 |
| 智能版 | 300 | 10000 | 20 |
| 专业版 | 1000 | 50000 | 50 |
| 企业版 | 无限制 | 无限制 | 200 |
处理速率限制
javascript
async function callWithRateLimit(fn) {
try {
return await fn();
} catch (error) {
if (error.status === 429) {
// 从响应头获取重试时间
const retryAfter = error.headers?.['retry-after'];
if (retryAfter) {
await sleep(parseInt(retryAfter) * 1000);
return await fn();
}
}
throw error;
}
}请求队列
javascript
class RequestQueue {
constructor(maxConcurrent = 5, minInterval = 1000) {
this.maxConcurrent = maxConcurrent;
this.minInterval = minInterval;
this.queue = [];
this.running = 0;
this.lastRequest = 0;
}
async add(fn) {
return new Promise((resolve, reject) => {
this.queue.push({ fn, resolve, reject });
this.process();
});
}
async process() {
if (this.running >= this.maxConcurrent || this.queue.length === 0) {
return;
}
const now = Date.now();
const timeSinceLastRequest = now - this.lastRequest;
if (timeSinceLastRequest < this.minInterval) {
setTimeout(() => this.process(), this.minInterval - timeSinceLastRequest);
return;
}
const { fn, resolve, reject } = this.queue.shift();
this.running++;
this.lastRequest = Date.now();
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
} finally {
this.running--;
this.process();
}
}
}
// 使用
const queue = new RequestQueue(5, 1000);
const response = await queue.add(() =>
client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
})
);最佳实践
1. 区分可重试和不可重试错误
javascript
function isRetryable(error) {
// 可重试:5xx、429、网络错误
if (error.status >= 500 || error.status === 429) {
return true;
}
if (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT') {
return true;
}
// 不可重试:4xx(除 429)
return false;
}2. 记录错误日志
javascript
try {
const response = await client.chat.completions.create({...});
} catch (error) {
console.error('API Error:', {
status: error.status,
code: error.code,
message: error.message,
timestamp: new Date().toISOString()
});
throw error;
}3. 用户友好的错误提示
javascript
function getUserFriendlyError(error) {
const errorMessages = {
401: '认证失败,请检查 API Key',
402: '余额不足,请充值',
429: '请求过于频繁,请稍后再试',
500: '服务暂时不可用,请稍后再试'
};
return errorMessages[error.status] || '请求失败,请重试';
}4. 监控和告警
javascript
// 记录错误率
const errorCount = new Map();
function trackError(error) {
const key = `${error.status}_${error.code}`;
errorCount.set(key, (errorCount.get(key) || 0) + 1);
// 错误率过高时告警
if (errorCount.get(key) > 10) {
sendAlert(`High error rate: ${key}`);
}
}常见问题
Q: 如何判断是否应该重试?
A: 5xx 错误和 429 错误应该重试,4xx 错误(除 429)不应该重试。
Q: 重试多少次合适?
A: 建议重试 3 次,使用指数退避策略。
Q: 如何避免速率限制?
A: 使用请求队列控制并发数,在请求间添加延迟。
Q: 余额不足怎么办?
A: 在控制台充值或升级套餐。