初次提交
This commit is contained in:
129
middleware/errorHandler.js
Normal file
129
middleware/errorHandler.js
Normal file
@@ -0,0 +1,129 @@
|
||||
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
|
||||
};
|
||||
Reference in New Issue
Block a user