const logger = require('./logger') /** * 公共错误处理工具类 * 提供统一的错误处理和响应格式 */ class ErrorHandler { /** * 处理 API 错误响应 * @param {Object} res - Express 响应对象 * @param {Error} error - 错误对象 * @param {string} requestId - 请求ID * @param {Object} context - 错误上下文信息 */ static handleApiError(res, error, requestId = null, context = {}) { const errorInfo = this.parseError(error) // 记录错误日志 if (requestId) { logger.logError(requestId, 'API_ERROR', errorInfo.message, { ...context, statusCode: errorInfo.statusCode, errorType: errorInfo.type }) } // 返回错误响应 res.status(errorInfo.statusCode).json({ error: { message: errorInfo.message, type: errorInfo.type, code: errorInfo.code } }) } /** * 处理模型调用错误 * @param {Object} res - Express 响应对象 * @param {Error} error - 错误对象 * @param {string} requestId - 请求ID * @param {string} model - 模型名称 * @param {boolean} isStream - 是否为流式请求 */ static handleModelError(res, error, requestId, model, isStream = false) { const errorInfo = this.parseError(error) logger.logError(requestId, 'MODEL_CALL_ERROR', errorInfo.message, { model, isStream, statusCode: errorInfo.statusCode, errorType: errorInfo.type }) // 特殊处理403错误(使用限制) if (errorInfo.statusCode === 403) { return this.handleRateLimitError(res, requestId, model) } // 返回通用错误响应 res.status(errorInfo.statusCode).json({ error: { message: errorInfo.message, type: errorInfo.type, code: errorInfo.code } }) } /** * 处理使用限制错误 * @param {Object} res - Express 响应对象 * @param {string} requestId - 请求ID * @param {string} model - 模型名称 */ static handleRateLimitError(res, requestId, model) { const errorMessage = `模型 ${model} 已达到使用限制,请稍后再试` logger.logError(requestId, 'RATE_LIMIT_ERROR', errorMessage, { model, statusCode: 429 }) res.status(429).json({ error: { message: errorMessage, type: 'rate_limit_exceeded', code: 'rate_limit_exceeded' } }) } /** * 处理图片上传错误 * @param {string} requestId - 请求ID * @param {Error} error - 错误对象 * @param {Object} context - 上下文信息 */ static handleImageUploadError(requestId, error, context = {}) { const errorInfo = this.parseError(error) logger.logError(requestId, 'IMAGE_UPLOAD_ERROR', errorInfo.message, { ...context, errorType: errorInfo.type }) throw new Error(`图片上传失败: ${errorInfo.message}`) } /** * 解析错误对象,提取关键信息 * @param {Error} error - 错误对象 * @returns {Object} 解析后的错误信息 */ static parseError(error) { let statusCode = 500 let message = '服务器内部错误' let type = 'server_error' let code = 'internal_error' if (error.response) { // Axios 错误 statusCode = error.response.status || 500 message = error.response.data?.message || error.response.data?.statusMessage || error.message || '请求失败' if (statusCode === 403) { type = 'rate_limit_exceeded' code = 'rate_limit_exceeded' } else if (statusCode === 401) { type = 'authentication_error' code = 'invalid_api_key' } else if (statusCode >= 400 && statusCode < 500) { type = 'client_error' code = 'bad_request' } } else if (error.code) { // 系统错误 if (error.code === 'ECONNREFUSED') { message = '连接被拒绝' type = 'connection_error' code = 'connection_refused' } else if (error.code === 'ETIMEDOUT') { message = '请求超时' type = 'timeout_error' code = 'request_timeout' statusCode = 408 } } else { // 普通错误 message = error.message || '未知错误' } return { statusCode, message, type, code } } /** * 创建标准化错误对象 * @param {string} message - 错误消息 * @param {number} statusCode - HTTP状态码 * @param {string} type - 错误类型 * @param {string} code - 错误代码 * @returns {Error} 标准化错误对象 */ static createError(message, statusCode = 500, type = 'server_error', code = 'internal_error') { const error = new Error(message) error.statusCode = statusCode error.type = type error.code = code return error } } module.exports = ErrorHandler