2025-11-04 21:51:05 +00:00
|
|
|
|
const config = require('../config');
|
2025-11-10 20:13:22 +00:00
|
|
|
|
const { log } = require('./logger');
|
2025-11-04 21:51:05 +00:00
|
|
|
|
|
|
|
|
|
|
// Централизованная обработка ошибок
|
|
|
|
|
|
const errorHandler = (err, req, res, next) => {
|
|
|
|
|
|
// Логирование ошибки
|
2025-11-10 20:13:22 +00:00
|
|
|
|
log('error', 'Ошибка обработчика', {
|
2025-11-04 21:51:05 +00:00
|
|
|
|
message: err.message,
|
|
|
|
|
|
stack: config.isDevelopment() ? err.stack : undefined,
|
|
|
|
|
|
path: req.path,
|
|
|
|
|
|
method: req.method,
|
|
|
|
|
|
ip: req.ip,
|
|
|
|
|
|
user: req.user?.id || 'anonymous'
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Определение типа ошибки и статус кода
|
|
|
|
|
|
let statusCode = err.statusCode || err.status || 500;
|
|
|
|
|
|
let message = err.message || 'Внутренняя ошибка сервера';
|
|
|
|
|
|
|
|
|
|
|
|
// Обработка специфических ошибок
|
|
|
|
|
|
if (err.name === 'ValidationError') {
|
|
|
|
|
|
statusCode = 400;
|
|
|
|
|
|
message = 'Ошибка валидации данных';
|
|
|
|
|
|
} else if (err.name === 'CastError') {
|
|
|
|
|
|
statusCode = 400;
|
|
|
|
|
|
message = 'Неверный формат данных';
|
|
|
|
|
|
} else if (err.name === 'MongoError' && err.code === 11000) {
|
|
|
|
|
|
statusCode = 409;
|
|
|
|
|
|
message = 'Дубликат записи';
|
|
|
|
|
|
} else if (err.name === 'MulterError') {
|
|
|
|
|
|
statusCode = 400;
|
|
|
|
|
|
if (err.code === 'LIMIT_FILE_SIZE') {
|
|
|
|
|
|
message = 'Файл слишком большой';
|
|
|
|
|
|
} else if (err.code === 'LIMIT_FILE_COUNT') {
|
|
|
|
|
|
message = 'Слишком много файлов';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
message = 'Ошибка загрузки файла';
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (err.name === 'AxiosError') {
|
|
|
|
|
|
statusCode = 502;
|
|
|
|
|
|
message = 'Ошибка внешнего сервиса';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Отправка ответа
|
|
|
|
|
|
res.status(statusCode).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
error: message,
|
|
|
|
|
|
...(config.isDevelopment() && { stack: err.stack })
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Обработка 404
|
|
|
|
|
|
const notFoundHandler = (req, res, next) => {
|
|
|
|
|
|
res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
error: 'Маршрут не найден'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Обработка необработанных промисов
|
|
|
|
|
|
process.on('unhandledRejection', (reason, promise) => {
|
2025-11-10 20:13:22 +00:00
|
|
|
|
log('error', 'Unhandled Rejection', { reason: reason instanceof Error ? reason.message : reason });
|
2025-11-04 21:51:05 +00:00
|
|
|
|
// В production можно отправить уведомление
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Обработка необработанных исключений
|
|
|
|
|
|
process.on('uncaughtException', (error) => {
|
2025-11-10 20:13:22 +00:00
|
|
|
|
log('error', 'Uncaught Exception', { message: error.message, stack: error.stack });
|
2025-11-04 21:51:05 +00:00
|
|
|
|
// Graceful shutdown
|
|
|
|
|
|
process.exit(1);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
|
|
errorHandler,
|
|
|
|
|
|
notFoundHandler
|
|
|
|
|
|
};
|
|
|
|
|
|
|