/**
* 错误处理工具类
* 提供统一的错误处理、分类和响应机制
*/
const Logger = require('./logger.js');
// const config = require('../config/config.js'); // 暂时注释掉,因为config.js不存在
/**
* 错误类型枚举
*/
const ErrorTypes = {
VALIDATION_ERROR: 'VALIDATION_ERROR',
CALCULATION_ERROR: 'CALCULATION_ERROR',
DATA_ERROR: 'DATA_ERROR',
SYSTEM_ERROR: 'SYSTEM_ERROR',
NETWORK_ERROR: 'NETWORK_ERROR',
TIMEOUT_ERROR: 'TIMEOUT_ERROR',
PERMISSION_ERROR: 'PERMISSION_ERROR',
RATE_LIMIT_ERROR: 'RATE_LIMIT_ERROR',
MCP_ERROR: 'MCP_ERROR',
UNKNOWN_ERROR: 'UNKNOWN_ERROR'
};
/**
* 错误严重级别
*/
const ErrorSeverity = {
LOW: 'low',
MEDIUM: 'medium',
HIGH: 'high',
CRITICAL: 'critical'
};
/**
* 自定义错误类
*/
class MCPError extends Error {
constructor(message, type = ErrorTypes.UNKNOWN_ERROR, severity = ErrorSeverity.MEDIUM, details = {}) {
super(message);
this.name = 'MCPError';
this.type = type;
this.severity = severity;
this.details = details;
this.timestamp = new Date().toISOString();
this.stack = Error.captureStackTrace ? Error.captureStackTrace(this, MCPError) : (new Error()).stack;
}
/**
* 转换为JSON格式
* @returns {Object} JSON对象
*/
toJSON() {
return {
name: this.name,
message: this.message,
type: this.type,
severity: this.severity,
details: this.details,
timestamp: this.timestamp,
stack: process.env.NODE_ENV === 'development' ? this.stack : undefined
};
}
/**
* 获取用户友好的错误消息
* @returns {string} 用户友好的错误消息
*/
getUserMessage() {
const userMessages = {
[ErrorTypes.VALIDATION_ERROR]: '输入参数有误,请检查后重试',
[ErrorTypes.CALCULATION_ERROR]: '计算过程中出现错误,请稍后重试',
[ErrorTypes.DATA_ERROR]: '数据处理错误,请检查输入数据',
[ErrorTypes.SYSTEM_ERROR]: '系统内部错误,请联系管理员',
[ErrorTypes.NETWORK_ERROR]: '网络连接错误,请检查网络状态',
[ErrorTypes.TIMEOUT_ERROR]: '请求超时,请稍后重试',
[ErrorTypes.PERMISSION_ERROR]: '权限不足,无法执行此操作',
[ErrorTypes.RATE_LIMIT_ERROR]: '请求过于频繁,请稍后重试',
[ErrorTypes.MCP_ERROR]: 'MCP协议错误,请检查客户端配置',
[ErrorTypes.UNKNOWN_ERROR]: '未知错误,请联系技术支持'
};
return userMessages[this.type] || this.message;
}
}
/**
* 错误处理器类
*/
class ErrorHandler {
constructor() {
this.logger = new Logger();
this.errorStats = new Map();
this.setupGlobalHandlers();
}
/**
* 设置全局错误处理器
*/
setupGlobalHandlers() {
// 处理未捕获的异常
process.on('uncaughtException', (error) => {
this.handleCriticalError(error, 'uncaughtException');
});
// 处理未处理的Promise拒绝
process.on('unhandledRejection', (reason, promise) => {
this.handleCriticalError(reason, 'unhandledRejection', { promise });
});
// 处理警告
process.on('warning', (warning) => {
this.logger.warn('Node.js警告', {
name: warning.name,
message: warning.message,
stack: warning.stack
});
});
}
/**
* 处理关键错误
* @param {Error} error - 错误对象
* @param {string} source - 错误来源
* @param {Object} context - 上下文信息
*/
handleCriticalError(error, source, context = {}) {
const mcpError = this.wrapError(error, ErrorTypes.SYSTEM_ERROR, ErrorSeverity.CRITICAL);
this.logger.error('关键系统错误', {
source,
error: mcpError.toJSON(),
context,
pid: process.pid,
memory: process.memoryUsage(),
uptime: process.uptime()
});
// 在生产环境中,关键错误可能需要重启服务
if (process.env.NODE_ENV === 'production' && source === 'uncaughtException') {
this.logger.error('由于未捕获异常,服务将在5秒后退出');
setTimeout(() => {
process.exit(1);
}, 5000);
}
}
/**
* 包装错误为MCPError
* @param {Error|string} error - 错误对象或消息
* @param {string} type - 错误类型
* @param {string} severity - 错误严重级别
* @param {Object} details - 错误详情
* @returns {MCPError} MCP错误对象
*/
wrapError(error, type = ErrorTypes.UNKNOWN_ERROR, severity = ErrorSeverity.MEDIUM, details = {}) {
if (error instanceof MCPError) {
return error;
}
const message = error instanceof Error ? error.message : String(error);
const mcpError = new MCPError(message, type, severity, {
...details,
originalError: error instanceof Error ? {
name: error.name,
message: error.message,
stack: error.stack
} : null
});
return mcpError;
}
/**
* 处理工具调用错误
* @param {Error} error - 错误对象
* @param {string} toolName - 工具名称
* @param {Object} params - 工具参数
* @returns {Object} 错误响应
*/
handleToolError(error, toolName, params = {}) {
const mcpError = this.classifyError(error);
// 记录错误统计
this.recordErrorStats(mcpError.type, toolName);
// 记录错误日志
this.logger.error('工具调用错误', {
tool: toolName,
params: this.sanitizeParams(params),
error: mcpError.toJSON()
});
// 返回符合MCP协议的错误响应
return {
content: [
{
type: 'text',
text: `工具调用失败: ${mcpError.getUserMessage()}`
}
],
isError: true
};
}
/**
* 分类错误类型
* @param {Error} error - 错误对象
* @returns {MCPError} 分类后的错误
*/
classifyError(error) {
if (error instanceof MCPError) {
return error;
}
let type = ErrorTypes.UNKNOWN_ERROR;
let severity = ErrorSeverity.MEDIUM;
// 根据错误消息和类型进行分类
if (error.name === 'ValidationError' || error.message.includes('validation')) {
type = ErrorTypes.VALIDATION_ERROR;
severity = ErrorSeverity.LOW;
} else if (error.name === 'TypeError' || error.name === 'ReferenceError') {
type = ErrorTypes.CALCULATION_ERROR;
severity = ErrorSeverity.MEDIUM;
} else if (error.name === 'SyntaxError') {
type = ErrorTypes.DATA_ERROR;
severity = ErrorSeverity.MEDIUM;
} else if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
type = ErrorTypes.NETWORK_ERROR;
severity = ErrorSeverity.HIGH;
} else if (error.code === 'ETIMEDOUT' || error.message.includes('timeout')) {
type = ErrorTypes.TIMEOUT_ERROR;
severity = ErrorSeverity.MEDIUM;
} else if (error.code === 'EACCES' || error.code === 'EPERM') {
type = ErrorTypes.PERMISSION_ERROR;
severity = ErrorSeverity.HIGH;
} else if (error.message.includes('rate limit')) {
type = ErrorTypes.RATE_LIMIT_ERROR;
severity = ErrorSeverity.LOW;
} else if (error.message.includes('MCP') || error.message.includes('protocol')) {
type = ErrorTypes.MCP_ERROR;
severity = ErrorSeverity.HIGH;
}
return this.wrapError(error, type, severity);
}
/**
* 创建错误响应
* @param {MCPError} error - MCP错误对象
* @param {string} toolName - 工具名称
* @returns {Object} 错误响应
*/
createErrorResponse(error, toolName) {
const response = {
isError: true,
error: {
type: error.type,
message: error.getUserMessage(),
severity: error.severity,
timestamp: error.timestamp,
tool: toolName
}
};
// 在开发环境中包含更多调试信息
if (process.env.NODE_ENV === 'development') {
response.error.details = error.details;
response.error.stack = error.stack;
response.error.originalMessage = error.message;
}
return response;
}
/**
* 记录错误统计
* @param {string} errorType - 错误类型
* @param {string} toolName - 工具名称
*/
recordErrorStats(errorType, toolName) {
const key = `${toolName}:${errorType}`;
const current = this.errorStats.get(key) || { count: 0, lastOccurred: null };
this.errorStats.set(key, {
count: current.count + 1,
lastOccurred: new Date().toISOString()
});
// 定期清理统计数据
if (this.errorStats.size > 1000) {
this.cleanupErrorStats();
}
}
/**
* 清理错误统计数据
*/
cleanupErrorStats() {
const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000); // 24小时前
for (const [key, stats] of this.errorStats.entries()) {
if (new Date(stats.lastOccurred) < cutoff) {
this.errorStats.delete(key);
}
}
}
/**
* 获取错误统计
* @returns {Object} 错误统计数据
*/
getErrorStats() {
const stats = {};
for (const [key, data] of this.errorStats.entries()) {
const [tool, type] = key.split(':');
if (!stats[tool]) {
stats[tool] = {};
}
stats[tool][type] = data;
}
return stats;
}
/**
* 清理敏感参数
* @param {Object} params - 参数对象
* @returns {Object} 清理后的参数
*/
sanitizeParams(params) {
const sensitiveKeys = ['password', 'token', 'key', 'secret', 'auth'];
const sanitized = { ...params };
for (const key of Object.keys(sanitized)) {
if (sensitiveKeys.some(sensitive => key.toLowerCase().includes(sensitive))) {
sanitized[key] = '[REDACTED]';
}
}
return sanitized;
}
/**
* 验证错误恢复
* @param {Function} operation - 要执行的操作
* @param {Object} options - 恢复选项
* @returns {Promise<*>} 操作结果
*/
async withRetry(operation, options = {}) {
const {
maxAttempts = 3,
delay = 1000,
backoff = true,
retryCondition = (error) => error.severity !== ErrorSeverity.CRITICAL
} = options;
let lastError;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await operation();
} catch (error) {
lastError = this.classifyError(error);
// 检查是否应该重试
if (attempt === maxAttempts || !retryCondition(lastError)) {
throw lastError;
}
// 计算延迟时间
const currentDelay = backoff ? delay * Math.pow(2, attempt - 1) : delay;
this.logger.warn('操作失败,准备重试', {
attempt,
maxAttempts,
delay: currentDelay,
error: lastError.toJSON()
});
// 等待后重试
await new Promise(resolve => setTimeout(resolve, currentDelay));
}
}
throw lastError;
}
/**
* 创建验证错误
* @param {string} message - 错误消息
* @param {Object} details - 错误详情
* @returns {MCPError} 验证错误
*/
createValidationError(message, details = {}) {
return new MCPError(message, ErrorTypes.VALIDATION_ERROR, ErrorSeverity.LOW, details);
}
/**
* 创建计算错误
* @param {string} message - 错误消息
* @param {Object} details - 错误详情
* @returns {MCPError} 计算错误
*/
createCalculationError(message, details = {}) {
return new MCPError(message, ErrorTypes.CALCULATION_ERROR, ErrorSeverity.MEDIUM, details);
}
/**
* 创建数据错误
* @param {string} message - 错误消息
* @param {Object} details - 错误详情
* @returns {MCPError} 数据错误
*/
createDataError(message, details = {}) {
return new MCPError(message, ErrorTypes.DATA_ERROR, ErrorSeverity.MEDIUM, details);
}
/**
* 创建系统错误
* @param {string} message - 错误消息
* @param {Object} details - 错误详情
* @returns {MCPError} 系统错误
*/
createSystemError(message, details = {}) {
return new MCPError(message, ErrorTypes.SYSTEM_ERROR, ErrorSeverity.HIGH, details);
}
/**
* 通用错误处理方法
* @param {Error} error - 错误对象
* @param {string} context - 错误上下文
* @param {Object} details - 额外详情
* @returns {MCPError} 处理后的错误
*/
handleError(error, context = 'unknown', details = {}) {
const mcpError = this.classifyError(error);
// 记录错误日志
this.logger.error('错误处理', {
context,
error: mcpError.toJSON(),
details
});
return mcpError;
}
}
// 导出错误类型和处理器
module.exports = {
ErrorTypes,
ErrorSeverity,
MCPError,
ErrorHandler
};
module.exports.default = ErrorHandler;