Как обрабатывать ошибки async/await в обработчиках маршрутов Express?
В Express 4 async-хэндлеры не ловят ошибки автоматически — нужно либо явный try/catch с next(err), либо обёртка asyncHandler; Express 5 поддерживает async нативно.
Обработка ошибок async/await в маршрутах Express
Express 4 не умеет перехватывать ошибки из async-функций автоматически — необработанный rejected Promise просто зависнет или упадёт с UnhandledPromiseRejection. Есть три рабочих подхода.
1. Явный try/catch с передачей в next
import express, { Request, Response, NextFunction } from 'express';
const router = express.Router();
router.get('/users/:id', async (req: Request, res: Response, next: NextFunction) => {
try {
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
if (!user.rows.length) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user.rows[0]);
} catch (err) {
next(err); // передаём в error middleware
}
});
Это самый явный способ — понятно, что происходит, и нет магии. Минус: много шаблонного кода при большом числе маршрутов.
2. Обёртка asyncHandler
Создаём утилиту, которая оборачивает async-хэндлер и автоматически пробрасывает ошибки в next:
// utils/asyncHandler.ts
import { Request, Response, NextFunction, RequestHandler } from 'express';
type AsyncFn = (req: Request, res: Response, next: NextFunction) => Promise<unknown>;
export const asyncHandler = (fn: AsyncFn): RequestHandler =>
(req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// routes/users.ts
import { asyncHandler } from '../utils/asyncHandler';
router.get('/users/:id', asyncHandler(async (req, res) => {
const user = await userService.findById(req.params.id);
res.json(user);
}));
Такой же паттерн предоставляет популярный пакет express-async-errors — он патчит сам Express и делает это глобально.
3. Express 5 (нативная поддержка)
В Express 5 (npm install express@^5) async-хэндлеры поддерживаются из коробки: отклонённый Promise автоматически вызывает next(err) без каких-либо обёрток.
// Express 5 — работает нативно
app.get('/items', async (req, res) => {
const items = await itemService.getAll(); // если бросит — Express сам поймает
res.json(items);
});
Error middleware (обязателен в любом случае)
// app.ts — регистрируется последним, ПОСЛЕ всех маршрутов
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error(err.stack);
const status = (err as any).status ?? 500;
res.status(status).json({
error: process.env.NODE_ENV === 'production' ? 'Internal server error' : err.message,
});
});
Подводные камни
- Забыть вызвать next(err) — без него Express продолжит выполнение или зависнет с таймаутом.
- Express 4 не ловит async без обёртки — UnhandledPromiseRejection в Node.js приводит к падению процесса (или ignoring в старых версиях Node).
- Error middleware без 4 аргументов не работает — Express определяет error middleware строго по сигнатуре
(err, req, res, next); если убратьnext, он перестаёт быть error middleware. - Регистрация error middleware до маршрутов — она должна быть последней в цепочке
app.use(), иначе ошибки до неё не дойдут. - Утечка стека в production — никогда не отправляйте
err.stackклиенту; фильтруйте поNODE_ENV. - Повторный вызов res.json() после next(err) — если в catch вызвать и
res.json(), иnext(err), будет «Cannot set headers after they are sent». - Ошибки внутри setTimeout/setInterval не перехватываются — async/await здесь не поможет; используйте отдельный try/catch или worker threads.
Common mistakes
- Дает общий ответ про Node.js и не называет конкретные API Express.js.
- Не объясняет, где в lifecycle находится ошибки async/await в route handlers.
- Не разделяет validation, authorization, business logic и persistence.
- Игнорирует ошибки, лимиты входных данных, observability и тестирование.
What the interviewer is testing
- Может объяснить ошибки async/await в route handlers на примере кода.
- Называет ключевые API: async (req, res), next(err).
- Использует точные API Express.js, а не вымышленные hooks/decorators/methods.
- Видит production-риски: безопасность, отказоустойчивость, логирование и тесты.