Skip to main content

错误响应格式

所有错误响应遵循统一格式:
标准错误响应格式
{
  "error": "ErrorType",
  "message": "Human-readable error message",
  "details": {
    "key": "additional info"
  },
  "statusCode": 400,
  "correlationId": "req_abc123"
}
响应头
X-Correlation-Id: req_abc123
字段说明
  • error: 错误类型(对应 HTTP 状态码)
  • message: 人类可读的错误描述
  • details: 可选的额外错误信息
  • statusCode: HTTP 状态码
  • correlationId: 用于追踪请求的唯一标识符(注意:401 认证错误不包含此字段)
  • X-Correlation-Id 响应头:与响应体中的 correlationId 相同(注意:401 错误也不包含此响应头)

HTTP 状态码

状态码类型说明
400BadRequest请求参数错误
401Unauthorized认证失败
403Forbidden权限不足
404NotFound资源不存在
409Conflict资源冲突
429TooManyRequests超过速率限制(⚠️ 当前未实现限流功能)
500InternalServerError服务器内部错误
503ServiceUnavailable服务暂时不可用

常见错误

错误响应层级说明
  • 401 认证错误:在 middleware 层处理
    • 响应体格式:{error, message, statusCode}(无 correlationIddetails
    • 响应头:不包含 X-Correlation-Id
  • 其他错误(400、403、500 等):在 API 路由层处理
    • 响应体格式:{error, message, statusCode, correlationId, details?}
    • 响应头:包含 X-Correlation-Id
  • 429 错误:当前未实现,不会返回此错误(错误类型已定义但未使用)

401 Unauthorized

原因:API Key 无效、缺失或格式错误 认证失败有以下几种情况,错误消息会相应变化:
401 错误响应
{
  "error": "Unauthorized",
  "message": "Missing authorization header",
  "statusCode": 401
}
401 错误响应
{
  "error": "Unauthorized",
  "message": "Invalid authorization format. Use: Bearer <token>",
  "statusCode": 401
}
401 错误响应
{
  "error": "Unauthorized",
  "message": "Invalid or expired API key",
  "statusCode": 401
}
注意:401 认证错误在 middleware 层处理,响应中不包含 correlationId 字段,响应头中也不包含 X-Correlation-Id。只有进入 API 路由后的错误(400、403、500 等)才在响应体和响应头中同时包含 correlationId。(429 当前未实现)
解决方案
  1. 检查 API Key 是否正确
  2. 确认 Authorization 头格式:Bearer YOUR_API_KEY
  3. 验证 API Key 是否已过期
  4. 确认外部认证服务是否可用

403 Forbidden

原因:模型或工具不在许可列表中
403 错误响应
{
  "error": "Forbidden",
  "message": "Model not available with your API key",
  "statusCode": 403,
  "correlationId": "req_def456"
}
解决方案
  • 使用 GET /api/v1/models 查看可用模型
  • 使用 GET /api/v1/tools 查看可用工具
  • 联系管理员升级权限

400 BadRequest - 缺少必需上下文

原因:工具缺少必需的上下文参数
400 错误响应
{
  "error": "BadRequest",
  "message": "Missing required context: configData, replyPrompts",
  "details": {
    "error": "Missing required context: configData, replyPrompts",
    "missingContext": ["configData", "replyPrompts"]
  },
  "statusCode": 400,
  "correlationId": "req_ghi789"
}
注意details.error 字段包含与 message 相同的错误描述,missingContext 数组列出了所有缺失的上下文字段名称。
解决方案
  1. 使用 GET /api/v1/tools 查看工具的 requiredContext
  2. contexttoolContext 中提供缺失的字段
  3. 或使用 contextStrategy: "skip" 跳过该工具

429 TooManyRequests(当前未实现)

实现状态
  • ❌ 当前 API 未实现速率限制功能
  • ❌ 不会返回 429 错误响应
  • ❌ 不会设置 Retry-After 响应头
  • ✅ 错误类型已定义(TooManyRequests),但未在代码中使用
  • 💡 如需限流,建议在网关层或 middleware 实现
理论响应格式(如果实现):
429 错误响应(理论)
{
  "error": "TooManyRequests",
  "message": "Rate limit exceeded",
  "statusCode": 429,
  "correlationId": "req_jkl012"
}
设计说明:如果未来实现限流功能,建议通过 HTTP 响应头 Retry-After(单位:秒)传递重试等待时间:
Retry-After: 10
如果实现,建议的客户端处理策略
  • 实现指数退避重试策略
  • 读取响应头 Retry-After 获取建议的重试时间
  • 减少并发请求数
  • 联系销售团队提升限额

500 InternalServerError

原因:服务器内部错误
500 错误响应
{
  "error": "InternalServerError",
  "message": "An unexpected error occurred",
  "statusCode": 500,
  "correlationId": "req_mno345"
}
重要:遇到 500 错误时,请务必记录 correlationId 并联系技术支持,这将帮助快速定位问题。
解决方案
  • 使用 correlationId 联系技术支持
  • 稍后重试
  • 检查服务状态页

错误处理最佳实践

基础错误处理
try {
  const response = await fetch(url, options);

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`API Error: ${error.message}`);
  }

  const data = await response.json();
  return data;
} catch (error) {
  console.error('请求失败:', error);
  // 向用户展示友好的错误信息
}
重试机制实现
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);

      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After') || 5;
        await sleep(retryAfter * 1000);
        continue;
      }

      return response;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await sleep(Math.pow(2, i) * 1000); // 指数退避
    }
  }
}
关键点
  • ⚠️ 当前 API 未实现 429 限流,上述代码为未来兼容性保留
  • 其他错误使用指数退避策略(2^i 秒:1s, 2s, 4s)
  • 如果未来实现 429,建议读取 Retry-After 响应头
记录 correlationId
const response = await fetch(url, options);
const data = await response.json();

// 优先从响应体获取(错误响应),失败则从响应头获取(成功响应)
const correlationId =
  data.correlationId ||
  response.headers.get('X-Correlation-Id');

if (!response.ok) {
  console.error('Error correlationId:', correlationId);
  // 记录到日志系统,便于排查问题
} else {
  console.log('Success correlationId:', correlationId);
  // 成功请求也应记录 correlationId,便于追踪
}
correlationId 获取方式
  • 错误响应:从响应体 data.correlationId 或响应头 X-Correlation-Id 获取(两者相同)
  • 成功响应:只能从响应头 X-Correlation-Id 获取(响应体不包含)
  • 401 错误:两处都不包含,无法获取 correlationId
  • 联系技术支持时提供此 ID 可以快速定位问题
错误类型处理
function handleError(error) {
  switch (error.statusCode) {
    case 401:
      // 重新认证
      redirectToLogin();
      break;
    case 403:
      // 权限不足提示
      showPermissionError();
      break;
    case 429:
      // 限流提示(当前不会触发,为未来兼容性保留)
      showRateLimitWarning();
      break;
    case 500:
      // 服务器错误
      showServerError(error.correlationId);
      break;
    default:
      showGenericError();
  }
}
注意:当前 API 不会返回 429 错误(未实现限流),case 429 为未来兼容性保留。

完整示例

实现状态说明:示例代码中包含 429 限流处理逻辑,但当前 API 未实现限流功能,不会返回 429 错误。该逻辑为未来兼容性保留,建议保留以便将来 API 添加限流功能时无需修改代码。
async function safeChat(message, options = {}) {
  const maxRetries = 3;
  let lastError = null;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch("https://huajune.duliday.com/api/v1/chat", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${apiKey}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          model: "anthropic/claude-3-7-sonnet-20250219",
          messages: [{ role: "user", content: message }],
          ...options,
        }),
      });

      // 429 处理(当前不会触发,为未来兼容性保留)
      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get("Retry-After") || "5");
        console.log(`Rate limited, retrying after ${retryAfter}s`);
        await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
        continue;
      }

      const data = await response.json();

      // 获取 correlationId:优先从响应体,失败则从响应头
      const correlationId =
        data.correlationId || response.headers.get("X-Correlation-Id");

      if (!response.ok) {
        console.error(`Error (${correlationId}):`, data.message);
        throw new Error(data.message);
      }

      return data;
    } catch (error) {
      lastError = error;

      if (attempt < maxRetries - 1) {
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms`);
        await new Promise((resolve) => setTimeout(resolve, delay));
      }
    }
  }

  throw lastError;
}

// 使用
try {
  const result = await safeChat("你好");
  console.log(result.data.messages[0].parts[0].text);
} catch (error) {
  console.error("聊天失败:", error.message);
}
完整示例特点
  • ⚠️ 包含 429 限流处理(当前未实现,为未来兼容性保留)
  • ✅ 网络错误等使用指数退避重试(1s, 2s, 4s)
  • ✅ 正确获取 correlationId:优先从响应体,失败则从响应头 X-Correlation-Id
  • ✅ 记录 correlationId 便于问题追踪
  • ✅ 最多重试 3 次后抛出最后一次的错误
  • 💡 建议保留 429 处理逻辑,以便 API 未来添加限流时无需修改代码

调试技巧

关于成功响应的 correlationId成功响应(200 OK)的响应体中不包含 correlationId 字段,但响应头中包含 X-Correlation-Id。建议在所有请求(成功或失败)中记录此响应头,便于追踪完整的请求链路。获取方式
  • JavaScript: response.headers.get('X-Correlation-Id')
  • Python (requests): response.headers.get('X-Correlation-Id')

记录 correlationId

保存每个请求的 correlationId(响应体或响应头),便于问题排查

使用 validateOnly

在正式调用前验证参数配置

监控错误率

跟踪不同类型错误的发生频率

日志记录

记录完整的请求和响应,便于复现问题

下一步