/** * API响应格式标准化工具 * 统一前后端接口返回格式 */ /** * 创建标准成功响应 * @param {*} data - 响应数据 * @param {string} message - 响应消息 * @param {Object} options - 其他选项 * @returns {Object} 标准响应格式 */ const createSuccessResponse = (data = null, message = '操作成功', options = {}) => { const response = { success: true, message, data, timestamp: new Date().toISOString(), requestId: options.requestId || generateRequestId() }; // 添加分页信息 if (options.total !== undefined) { response.total = options.total; } if (options.page !== undefined) { response.page = options.page; } if (options.limit !== undefined) { response.limit = options.limit; } // 添加元数据 if (options.meta) { response.meta = options.meta; } return response; }; /** * 创建标准错误响应 * @param {string} message - 错误消息 * @param {string} code - 错误代码 * @param {*} details - 错误详情 * @param {Object} options - 其他选项 * @returns {Object} 标准错误响应格式 */ const createErrorResponse = (message = '操作失败', code = 'UNKNOWN_ERROR', details = null, options = {}) => { return { success: false, message, code, details, timestamp: new Date().toISOString(), requestId: options.requestId || generateRequestId() }; }; /** * 创建分页响应 * @param {Array} data - 数据列表 * @param {number} total - 总记录数 * @param {number} page - 当前页码 * @param {number} limit - 每页记录数 * @param {string} message - 响应消息 * @param {Object} options - 其他选项 * @returns {Object} 分页响应格式 */ const createPaginatedResponse = (data, total, page, limit, message = '获取数据成功', options = {}) => { return createSuccessResponse(data, message, { total, page, limit, ...options }); }; /** * 生成请求ID * @returns {string} 请求ID */ const generateRequestId = () => { return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; }; /** * 错误代码常量 */ const ERROR_CODES = { // 认证相关 UNAUTHORIZED: 'UNAUTHORIZED', TOKEN_EXPIRED: 'TOKEN_EXPIRED', INVALID_TOKEN: 'INVALID_TOKEN', // 权限相关 FORBIDDEN: 'FORBIDDEN', INSUFFICIENT_PERMISSIONS: 'INSUFFICIENT_PERMISSIONS', // 资源相关 NOT_FOUND: 'NOT_FOUND', RESOURCE_CONFLICT: 'RESOURCE_CONFLICT', RESOURCE_LOCKED: 'RESOURCE_LOCKED', // 验证相关 VALIDATION_ERROR: 'VALIDATION_ERROR', INVALID_INPUT: 'INVALID_INPUT', MISSING_REQUIRED_FIELD: 'MISSING_REQUIRED_FIELD', // 业务相关 BUSINESS_ERROR: 'BUSINESS_ERROR', OPERATION_FAILED: 'OPERATION_FAILED', DUPLICATE_ENTRY: 'DUPLICATE_ENTRY', // 系统相关 INTERNAL_ERROR: 'INTERNAL_ERROR', SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE', DATABASE_ERROR: 'DATABASE_ERROR', NETWORK_ERROR: 'NETWORK_ERROR', // 未知错误 UNKNOWN_ERROR: 'UNKNOWN_ERROR' }; /** * 成功消息常量 */ const SUCCESS_MESSAGES = { // 通用操作 OPERATION_SUCCESS: '操作成功', DATA_SAVED: '数据保存成功', DATA_UPDATED: '数据更新成功', DATA_DELETED: '数据删除成功', DATA_RETRIEVED: '数据获取成功', // 认证相关 LOGIN_SUCCESS: '登录成功', LOGOUT_SUCCESS: '登出成功', PASSWORD_CHANGED: '密码修改成功', // 文件相关 FILE_UPLOADED: '文件上传成功', FILE_DELETED: '文件删除成功', // 导出相关 EXPORT_SUCCESS: '数据导出成功', IMPORT_SUCCESS: '数据导入成功' }; /** * 统一错误处理中间件 * @param {Error} err - 错误对象 * @param {Object} req - 请求对象 * @param {Object} res - 响应对象 * @param {Function} next - 下一个中间件 */ const errorHandler = (err, req, res, next) => { console.error('API Error:', { message: err.message, stack: err.stack, url: req.url, method: req.method, body: req.body, query: req.query }); // 数据库错误 if (err.name === 'SequelizeError' || err.name === 'SequelizeValidationError') { return res.status(400).json(createErrorResponse( '数据库操作失败', ERROR_CODES.DATABASE_ERROR, err.message )); } // 验证错误 if (err.name === 'ValidationError') { return res.status(400).json(createErrorResponse( '数据验证失败', ERROR_CODES.VALIDATION_ERROR, err.message )); } // 认证错误 if (err.name === 'UnauthorizedError' || err.status === 401) { return res.status(401).json(createErrorResponse( '认证失败', ERROR_CODES.UNAUTHORIZED, err.message )); } // 权限错误 if (err.status === 403) { return res.status(403).json(createErrorResponse( '权限不足', ERROR_CODES.FORBIDDEN, err.message )); } // 资源不存在 if (err.status === 404) { return res.status(404).json(createErrorResponse( '资源不存在', ERROR_CODES.NOT_FOUND, err.message )); } // 默认服务器错误 res.status(500).json(createErrorResponse( '服务器内部错误', ERROR_CODES.INTERNAL_ERROR, process.env.NODE_ENV === 'development' ? err.message : '服务器繁忙,请稍后重试' )); }; module.exports = { createSuccessResponse, createErrorResponse, createPaginatedResponse, generateRequestId, ERROR_CODES, SUCCESS_MESSAGES, errorHandler };