Skip to content

错误处理

了解 OpenHub API 的错误码和处理方法。

错误响应格式

所有错误响应遵循统一格式:

json
{
  "success": false,
  "data": null,
  "error": {
    "code": "ERROR_CODE",
    "message": "错误描述"
  }
}

HTTP 状态码

状态码说明
200请求成功
400请求参数错误
401未认证或认证失败
403权限不足
404资源不存在
429请求频率超限
500服务器内部错误
503服务暂时不可用

错误码列表

认证错误

错误码HTTP 状态码说明解决方法
UNAUTHORIZED401未提供 API Key检查 Authorization header
INVALID_API_KEY401API Key 无效检查 API Key 是否正确
API_KEY_EXPIRED401API Key 已过期重新生成 API Key
FORBIDDEN403权限不足检查 API Key 权限设置

请求错误

错误码HTTP 状态码说明解决方法
INVALID_REQUEST400请求格式错误检查请求参数
MISSING_PARAMETER400缺少必填参数补充必填参数
INVALID_PARAMETER400参数值无效检查参数值范围
MODEL_NOT_FOUND404模型不存在使用正确的模型名称

资源错误

错误码HTTP 状态码说明解决方法
INSUFFICIENT_BALANCE402余额不足充值或升级套餐
QUOTA_EXCEEDED429配额超限等待配额重置或升级套餐
RATE_LIMIT_EXCEEDED429请求频率超限降低请求频率

内容错误

错误码HTTP 状态码说明解决方法
CONTENT_VIOLATION400内容违规修改请求内容
CONTENT_TOO_LONG400内容过长减少输入长度

服务错误

错误码HTTP 状态码说明解决方法
INTERNAL_ERROR500服务器内部错误重试或联系支持
SERVICE_UNAVAILABLE503服务暂时不可用稍后重试
TIMEOUT504请求超时重试或减少输入长度

错误处理示例

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;
}

速率限制

限制说明

不同套餐有不同的速率限制:

套餐每分钟请求数每天请求数并发数
免费版6010005
智能版3001000020
专业版10005000050
企业版无限制无限制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: 在控制台充值或升级套餐。

下一步

Released under the MIT License.