229 lines
5.4 KiB
JavaScript
229 lines
5.4 KiB
JavaScript
/**
|
|
* 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
|
|
};
|