← Назад к вопросам
Как правильно обрабатывать uncaught exceptions и unhandled rejections в Node.js?
3.0 Senior🔥 291 комментариев
#Node.js и JavaScript#Безопасность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Обработка uncaught exceptions и unhandled rejections
В Node.js необработанные исключения и отклоненные промисы могут привести к аварийному завершению процесса и потере данных. Правильная обработка этих ситуаций критична для production-приложений.
Uncaught Exceptions
Uncaught exception возникает, когда синхронное исключение выбрасывается вне блока try/catch:
function processData(data: unknown) {
const parsed = JSON.parse(data as string);
return parsed.value.nested.prop;
}
// setTimeout callback - нет обертки try/catch
setTimeout(() => {
processData("invalid json"); // uncaught exception!
}, 1000);
Обработка через process events
process.on("uncaughtException", (error: Error, origin: string) => {
console.error("Uncaught Exception:", {
message: error.message,
stack: error.stack,
origin
});
// Отправить в систему мониторинга
logger.fatal("Uncaught exception", { error });
// ВАЖНО: после uncaughtException процесс в неопределенном состоянии
gracefulShutdown().then(() => process.exit(1));
});
process.on("unhandledRejection", (reason: unknown, promise: Promise<unknown>) => {
console.error("Unhandled Rejection:", reason);
logger.error("Unhandled rejection", {
reason: reason instanceof Error ? reason.message : String(reason)
});
});
Почему нельзя просто продолжить работу
После uncaughtException состояние приложения непредсказуемо:
- Обработчик мог прерваться на середине записи в БД
- Мьютексы и локи могут остаться захваченными
- Буферы могут быть в inconsistent состоянии
Документация Node.js явно предупреждает: после uncaughtException единственное безопасное действие - залогировать ошибку и завершить процесс.
Unhandled Rejections
// Пример 1: забыли await или catch
async function fetchData() {
const response = await fetch("https://api.example.com/data");
if (!response.ok) throw new Error("API error");
return response.json();
}
fetchData(); // unhandled rejection если ошибка!
// Правильно: fetchData().catch(handleError);
// Пример 2: ошибка внутри .then() без .catch()
Promise.resolve()
.then(() => { throw new Error("oops"); });
// нет .catch() -> unhandled rejection
Стратегия для production
1. Первый уровень - локальная обработка:
// Express error middleware
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
logger.error("Request error", {
error: err.message,
url: req.url,
method: req.method
});
res.status(500).json({ error: "Internal Server Error" });
});
// Обертка для async route handlers
function asyncHandler(fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) {
return (req: Request, res: Response, next: NextFunction) => {
fn(req, res, next).catch(next);
};
}
app.get("/users", asyncHandler(async (req, res) => {
const users = await userService.findAll();
res.json(users);
}));
2. Второй уровень - глобальные обработчики:
process.on("uncaughtException", fatalHandler);
process.on("unhandledRejection", fatalHandler);
3. Третий уровень - менеджер процессов:
PM2, systemd или Docker restart policy автоматически перезапустят упавший процесс.
Мониторинг и алертинг
import * as Sentry from "@sentry/node";
Sentry.init({ dsn: SENTRY_DSN });
process.on("uncaughtException", (error) => {
Sentry.captureException(error);
Sentry.flush(2000).then(() => process.exit(1));
});
Рекомендации
- Всегда используйте
.catch()для промисов илиtry/catchдляasync/await - Никогда не подавляйте ошибки (пустой catch)
- Используйте
asyncHandlerобертку для Express маршрутов - Настройте Sentry или аналог для отслеживания ошибок
- Пусть процесс падает и перезапускается - это безопаснее, чем работать в сломанном состоянии