You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
3.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 错误处理中间件
*
* 功能:
* 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
};