Files
2025-09-24 10:02:03 +08:00

129 lines
3.9 KiB
JavaScript

const { logger } = require('../config/logger');
const { ERROR_CODES, HTTP_STATUS } = require('../config/constants');
// 全局错误处理中间件
const errorHandler = (err, req, res, next) => {
let error = { ...err };
error.message = err.message;
// 记录错误日志
logger.error('Error occurred:', {
message: err.message,
stack: err.stack,
url: req.originalUrl,
method: req.method,
ip: req.ip,
userAgent: req.get('User-Agent'),
userId: req.user?.id
});
// MySQL错误处理
if (err.code) {
switch (err.code) {
case 'ER_DUP_ENTRY':
error.message = '数据已存在';
error.statusCode = HTTP_STATUS.CONFLICT;
error.errorCode = ERROR_CODES.DUPLICATE_ENTRY;
break;
case 'ER_NO_REFERENCED_ROW_2':
error.message = '关联数据不存在';
error.statusCode = HTTP_STATUS.BAD_REQUEST;
error.errorCode = ERROR_CODES.VALIDATION_ERROR;
break;
case 'ER_ROW_IS_REFERENCED_2':
error.message = '数据正在被使用,无法删除';
error.statusCode = HTTP_STATUS.CONFLICT;
error.errorCode = ERROR_CODES.VALIDATION_ERROR;
break;
case 'ECONNREFUSED':
error.message = '数据库连接失败';
error.statusCode = HTTP_STATUS.INTERNAL_SERVER_ERROR;
error.errorCode = ERROR_CODES.DATABASE_ERROR;
break;
default:
error.message = '数据库操作失败';
error.statusCode = HTTP_STATUS.INTERNAL_SERVER_ERROR;
error.errorCode = ERROR_CODES.DATABASE_ERROR;
}
}
// JWT错误处理
if (err.name === 'JsonWebTokenError') {
error.message = '无效的访问令牌';
error.statusCode = HTTP_STATUS.UNAUTHORIZED;
error.errorCode = ERROR_CODES.AUTHENTICATION_ERROR;
}
if (err.name === 'TokenExpiredError') {
error.message = '访问令牌已过期';
error.statusCode = HTTP_STATUS.UNAUTHORIZED;
error.errorCode = ERROR_CODES.AUTHENTICATION_ERROR;
}
// 参数验证错误
if (err.name === 'ValidationError' || err.isJoi) {
const message = err.details ? err.details.map(detail => detail.message).join(', ') : err.message;
error.message = `参数验证失败: ${message}`;
error.statusCode = HTTP_STATUS.BAD_REQUEST;
error.errorCode = ERROR_CODES.VALIDATION_ERROR;
}
// 业务逻辑错误处理
if (err.message === '余额不足') {
error.message = '用户积分余额不足,无法完成转账操作。请先为用户充值积分或选择其他用户。';
error.statusCode = HTTP_STATUS.BAD_REQUEST;
error.errorCode = ERROR_CODES.VALIDATION_ERROR;
}
if (err.message === '用户不存在') {
error.message = '指定的用户不存在,请检查用户信息后重试。';
error.statusCode = HTTP_STATUS.BAD_REQUEST;
error.errorCode = ERROR_CODES.VALIDATION_ERROR;
}
// 自定义错误
if (err.statusCode) {
error.statusCode = err.statusCode;
error.errorCode = err.errorCode || ERROR_CODES.INTERNAL_ERROR;
}
// 默认错误
const statusCode = error.statusCode || HTTP_STATUS.INTERNAL_SERVER_ERROR;
const errorCode = error.errorCode || ERROR_CODES.INTERNAL_ERROR;
const message = error.message || '服务器内部错误';
res.status(statusCode).json({
success: false,
error: {
code: errorCode,
message: message
},
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
};
// 404错误处理
const notFound = (req, res, next) => {
const error = new Error(`路径 ${req.originalUrl} 未找到`);
error.statusCode = HTTP_STATUS.NOT_FOUND;
error.errorCode = ERROR_CODES.NOT_FOUND;
next(error);
};
// 自定义错误类
class AppError extends Error {
constructor(message, statusCode, errorCode) {
super(message);
this.statusCode = statusCode;
this.errorCode = errorCode;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
module.exports = {
errorHandler,
notFound,
AppError
};