mamm / src /lib /errorHandler.js
nomid2's picture
Upload 4 files
c666a95 verified
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