Skip to main content
Glama
freefish1218

MCP HuggingFetch

by freefish1218
errors.js6.57 kB
/** * 错误处理模块 - 统一的错误定义和处理 */ // 错误码枚举 const ErrorCode = { NOT_FOUND: 'NOT_FOUND', UNAUTHORIZED: 'UNAUTHORIZED', FORBIDDEN: 'FORBIDDEN', RATE_LIMIT: 'RATE_LIMIT', SERVER_ERROR: 'SERVER_ERROR', NETWORK_ERROR: 'NETWORK_ERROR', TIMEOUT: 'TIMEOUT', INVALID_PARAMS: 'INVALID_PARAMS', LIMIT_EXCEEDED: 'LIMIT_EXCEEDED', INVALID_TOKEN: 'INVALID_TOKEN', PATH_TRAVERSAL: 'PATH_TRAVERSAL' }; /** * 统一的仓库错误类 */ class RepositoryError extends Error { constructor(code, message, details = null, suggestions = []) { super(message); this.name = 'RepositoryError'; this.code = code; this.details = details; this.suggestions = suggestions; } toJSON() { return { code: this.code, message: this.message, details: this.details, suggestions: this.suggestions }; } } /** * HTTP错误映射表 */ const HTTP_ERROR_MAP = { 401: { code: ErrorCode.UNAUTHORIZED, message: '认证失败', suggestions: ['检查 token 配置', '确认 token 是否有效'] }, 403: { code: ErrorCode.FORBIDDEN, message: '权限不足', suggestions: ['确认仓库访问权限', '如果是私有仓库,请提供有效的访问令牌'] }, 404: { code: ErrorCode.NOT_FOUND, message: '仓库或资源不存在', suggestions: ['检查仓库 ID 拼写', '确认仓库是否存在', '格式应为: owner/repo'] }, 429: { code: ErrorCode.RATE_LIMIT, message: '请求频率超限', suggestions: ['等待后重试', '使用指数退避策略', '提供认证令牌以获得更高限额'] } }; /** * 网络错误映射表 */ const NETWORK_ERROR_MAP = { ECONNRESET: { code: ErrorCode.NETWORK_ERROR, message: '连接被重置', suggestions: ['检查网络连接', '稍后重试'] }, ETIMEDOUT: { code: ErrorCode.TIMEOUT, message: '请求超时', suggestions: ['增加超时时间', '检查网络状况', '稍后重试'] }, ENOTFOUND: { code: ErrorCode.NETWORK_ERROR, message: '无法解析域名', suggestions: ['检查网络连接', '检查DNS设置'] }, ECONNREFUSED: { code: ErrorCode.NETWORK_ERROR, message: '连接被拒绝', suggestions: ['检查服务是否可用', '检查防火墙设置'] } }; /** * 将HTTP错误转换为RepositoryError */ function mapHttpError(error) { // 处理axios错误响应 if (error.response) { const status = error.response.status; const errorMap = HTTP_ERROR_MAP[status]; if (errorMap) { const details = { status, statusText: error.response.statusText, data: error.response.data }; // 特殊处理429错误的retry-after if (status === 429) { const retryAfter = error.response.headers['retry-after']; if (retryAfter) { details.retryAfter = parseInt(retryAfter); const suggestions = [...errorMap.suggestions]; suggestions[0] = `请等待 ${retryAfter} 秒后重试`; return new RepositoryError( errorMap.code, errorMap.message, details, suggestions ); } } return new RepositoryError( errorMap.code, errorMap.message, details, errorMap.suggestions ); } // 5xx服务器错误 if (status >= 500) { return new RepositoryError( ErrorCode.SERVER_ERROR, `服务器错误: ${status}`, { status, statusText: error.response.statusText }, ['稍后重试', '如问题持续,请联系支持'] ); } } // 处理网络错误 if (error.code && NETWORK_ERROR_MAP[error.code]) { const errorMap = NETWORK_ERROR_MAP[error.code]; return new RepositoryError( errorMap.code, errorMap.message, { originalCode: error.code, message: error.message }, errorMap.suggestions ); } // 默认网络错误 return new RepositoryError( ErrorCode.NETWORK_ERROR, error.message || '网络请求失败', { originalError: error.toString() }, ['检查网络连接', '稍后重试'] ); } /** * 判断错误是否可重试 */ function isRetryableError(error) { if (error instanceof RepositoryError) { // 以下错误码可以重试 const retryableCodes = [ ErrorCode.RATE_LIMIT, ErrorCode.SERVER_ERROR, ErrorCode.NETWORK_ERROR, ErrorCode.TIMEOUT ]; return retryableCodes.includes(error.code); } // 原始错误判断 if (error.response) { const status = error.response.status; return status === 429 || status >= 500; } // 网络错误可重试 if (error.code) { return ['ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED'].includes(error.code); } return false; } /** * 验证参数错误 */ function createValidationError(field, message, value = null) { return new RepositoryError( ErrorCode.INVALID_PARAMS, `参数验证失败: ${message}`, { field, value }, [`请检查 ${field} 参数的值`] ); } /** * 用户友好的错误格式化 */ function formatUserError(error) { if (error instanceof RepositoryError) { const messages = { [ErrorCode.NOT_FOUND]: { title: '仓库未找到', icon: '❌' }, [ErrorCode.UNAUTHORIZED]: { title: '认证失败', icon: '🔒' }, [ErrorCode.FORBIDDEN]: { title: '权限不足', icon: '⛔' }, [ErrorCode.RATE_LIMIT]: { title: '请求频率限制', icon: '⏳' }, [ErrorCode.NETWORK_ERROR]: { title: '网络连接问题', icon: '🌐' }, [ErrorCode.TIMEOUT]: { title: '请求超时', icon: '⏱️' }, [ErrorCode.INVALID_PARAMS]: { title: '参数错误', icon: '⚠️' } }; const errorInfo = messages[error.code] || { title: '未知错误', icon: '❓' }; let result = `${errorInfo.icon} ${errorInfo.title}\n`; result += `详情: ${error.message}\n`; if (error.suggestions && error.suggestions.length > 0) { result += '\n建议:\n'; error.suggestions.forEach(suggestion => { result += ` • ${suggestion}\n`; }); } return result; } return `错误: ${error.message || error.toString()}`; } module.exports = { ErrorCode, RepositoryError, mapHttpError, isRetryableError, createValidationError, formatUserError, HTTP_ERROR_MAP, NETWORK_ERROR_MAP };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/freefish1218/mcp-huggingfetch'

If you have feedback or need assistance with the MCP directory API, please join our Discord server