|
|
/**
|
|
|
* 错误处理中间件
|
|
|
*
|
|
|
* 功能:
|
|
|
* 1. 捕获异步函数中的错误
|
|
|
* 2. 统一处理404错误
|
|
|
* 3. 统一处理所有错误
|
|
|
*/
|
|
|
|
|
|
const { error: errorResponse } = require('../utils/response');
|
|
|
|
|
|
/**
|
|
|
* 异步错误处理包装器
|
|
|
* @param {function} fn - 异步处理函数
|
|
|
* @returns {function} Express中间件函数
|
|
|
*
|
|
|
* 说明:在async函数中如果出错,会自动被catch捕获并传递给错误处理中间件
|
|
|
*
|
|
|
* 使用示例:
|
|
|
* router.get('/users', asyncHandler(async (req, res) => {
|
|
|
* const users = await User.findAll();
|
|
|
* res.json(users);
|
|
|
* }));
|
|
|
*/
|
|
|
const asyncHandler = (fn) => {
|
|
|
return (req, res, next) => {
|
|
|
// 执行异步函数,如果出错就传递给next
|
|
|
Promise.resolve(fn(req, res, next)).catch(next);
|
|
|
};
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 404 Not Found 错误处理
|
|
|
* 当请求的路由不存在时调用
|
|
|
*/
|
|
|
const notFound = (req, res, next) => {
|
|
|
const error = new Error(`请求的资源不存在 - ${req.originalUrl}`);
|
|
|
error.status = 404;
|
|
|
next(error); // 将错误传递给下一个错误处理中间件
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 全局错误处理中间件
|
|
|
* 捕获所有错误并返回统一格式的响应
|
|
|
*
|
|
|
* @param {Error} err - 错误对象
|
|
|
* @param {object} req - 请求对象
|
|
|
* @param {object} res - 响应对象
|
|
|
* @param {function} next - next函数
|
|
|
*/
|
|
|
const errorHandler = (err, req, res, next) => {
|
|
|
// 确定HTTP状态码
|
|
|
const statusCode = err.status || err.statusCode || 500;
|
|
|
|
|
|
// 记录错误日志
|
|
|
console.error('❌ 错误发生:');
|
|
|
console.error('时间:', new Date().toLocaleString());
|
|
|
console.error('路径:', req.method, req.originalUrl);
|
|
|
console.error('错误信息:', err.message);
|
|
|
|
|
|
// 在开发环境下打印错误堆栈
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
|
console.error('错误堆栈:', err.stack);
|
|
|
}
|
|
|
|
|
|
// 返回错误响应
|
|
|
res.status(statusCode).json({
|
|
|
...errorResponse(err.message, err.code),
|
|
|
// 开发环境返回详细错误信息
|
|
|
...(process.env.NODE_ENV === 'development' && {
|
|
|
stack: err.stack,
|
|
|
path: req.originalUrl
|
|
|
})
|
|
|
});
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 自定义错误类 - 业务逻辑错误
|
|
|
* 用于主动抛出可预期的业务错误
|
|
|
*
|
|
|
* 使用示例:
|
|
|
* if (!user) {
|
|
|
* throw new BusinessError('用户不存在', 404);
|
|
|
* }
|
|
|
*/
|
|
|
class BusinessError extends Error {
|
|
|
constructor(message, statusCode = 400, code = null) {
|
|
|
super(message);
|
|
|
this.statusCode = statusCode;
|
|
|
this.code = code;
|
|
|
this.name = 'BusinessError';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 自定义错误类 - 验证错误
|
|
|
* 用于数据验证失败的情况
|
|
|
*/
|
|
|
class ValidationError extends Error {
|
|
|
constructor(message, errors = []) {
|
|
|
super(message);
|
|
|
this.statusCode = 400;
|
|
|
this.errors = errors; // 详细的验证错误列表
|
|
|
this.name = 'ValidationError';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 自定义错误类 - 认证错误
|
|
|
* 用于身份认证失败的情况
|
|
|
*/
|
|
|
class AuthenticationError extends Error {
|
|
|
constructor(message = '认证失败,请先登录') {
|
|
|
super(message);
|
|
|
this.statusCode = 401;
|
|
|
this.name = 'AuthenticationError';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 自定义错误类 - 授权错误
|
|
|
* 用于权限不足的情况
|
|
|
*/
|
|
|
class AuthorizationError extends Error {
|
|
|
constructor(message = '权限不足') {
|
|
|
super(message);
|
|
|
this.statusCode = 403;
|
|
|
this.name = 'AuthorizationError';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 导出所有函数和类
|
|
|
module.exports = {
|
|
|
asyncHandler,
|
|
|
notFound,
|
|
|
errorHandler,
|
|
|
BusinessError,
|
|
|
ValidationError,
|
|
|
AuthenticationError,
|
|
|
AuthorizationError
|
|
|
};
|