Middleware в Iron представляет собой механизм промежуточной обработки запроса, позволяющий перехватывать поток выполнения маршрута до того, как он достигнет конечного обработчика. Такая архитектура формирует цепочку функций, каждая из которых получает доступ к контексту запроса, ответа и функции передачи управления далее по цепочке.
В Iron обработка запроса организуется как последовательный pipeline. Каждый middleware выполняется в порядке регистрации и имеет возможность:
Ключевым элементом является функция next, которая
активирует следующий слой цепочки.
app.use(async (ctx, next) => {
console.log("Запрос получен:", ctx.path);
await next();
});
Если next() не вызывается, выполнение цепочки
прерывается, и последующие middleware, включая конечный обработчик
маршрута, не выполняются.
Контекст в Iron служит единым объектом, содержащим данные запроса и ответа. Middleware часто используется для расширения этого контекста дополнительной информацией.
app.use(async (ctx, next) => {
ctx.requestTime = Date.now();
await next();
});
Такой подход позволяет последующим слоям использовать обогащённые данные без необходимости повторного вычисления.
Одним из основных сценариев middleware является контроль доступа к маршрутам. Проверка токена или сессии выполняется до попадания в бизнес-логику.
async function authMiddleware(ctx, next) {
const token = ctx.headers.authorization;
if (!token) {
ctx.status = 401;
ctx.body = { error: "Отсутствует токен доступа" };
return;
}
const user = verifyToken(token);
if (!user) {
ctx.status = 403;
ctx.body = { error: "Недействительный токен" };
return;
}
ctx.user = user;
await next();
}
Middleware подобного типа завершает выполнение при отсутствии доступа, предотвращая выполнение защищённых маршрутов.
Архитектура Iron позволяет применять middleware как глобально, так и на уровне конкретных маршрутов. Это создаёт разделение между открытыми и закрытыми частями API.
app.use(publicRouter.routes());
app.use(authMiddleware);
app.use(privateRouter.routes());
В такой конфигурации все маршруты, зарегистрированные после
authMiddleware, автоматически становятся защищёнными.
Расширение базовой авторизации заключается в проверке ролей пользователя. Middleware может анализировать свойства объекта пользователя и принимать решение о доступе.
function roleMiddleware(requiredRole) {
return async (ctx, next) => {
if (!ctx.user || ctx.user.role !== requiredRole) {
ctx.status = 403;
ctx.body = { error: "Недостаточно прав" };
return;
}
await next();
};
}
Использование цепочки middleware позволяет комбинировать проверки:
app.use(authMiddleware);
app.use(roleMiddleware("admin"));
Одной из сильных сторон Iron является возможность композиции middleware. Несколько функций могут быть объединены в единый поток обработки.
app.use(loggingMiddleware);
app.use(authMiddleware);
app.use(rateLimitMiddleware);
app.use(router.routes());
Порядок регистрации определяет порядок выполнения, что делает архитектуру предсказуемой и управляемой.
Ошибки, возникающие в процессе выполнения цепочки, могут быть централизованно обработаны через специальный middleware верхнего уровня.
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = 500;
ctx.body = {
error: "Внутренняя ошибка сервера"
};
}
});
Такой слой обеспечивает единообразную обработку исключений без необходимости дублирования логики в каждом маршруте.
Middleware в Iron поддерживает асинхронное выполнение, что критично для операций с базами данных, внешними API и файловой системой.
app.use(async (ctx, next) => {
ctx.userProfile = await db.users.findById(ctx.user.id);
await next();
});
Асинхронная модель позволяет сохранять линейную структуру кода при выполнении сложных операций.
Middleware может завершить обработку запроса на любом этапе. Это используется для кэширования, ограничения доступа или оптимизации.
app.use(async (ctx, next) => {
const cached = cache.get(ctx.path);
if (cached) {
ctx.body = cached;
return;
}
await next();
});
Прерывание цепочки снижает нагрузку на последующие слои системы.
Порядок подключения middleware определяет логику выполнения приложения. Ошибки в порядке могут привести к некорректной работе защиты маршрутов.
Типичный порядок:
app.use(errorHandler);
app.use(logger);
app.use(authMiddleware);
app.use(router.routes());
Middleware используется для отделения технической логики от бизнес-кода маршрутов. Это снижает связанность компонентов и упрощает сопровождение.
Маршрут остаётся минимальным:
router.get("/profile", async (ctx) => {
ctx.body = ctx.userProfile;
});
Вся подготовка данных выполняется на уровне middleware.
Каждый middleware является звеном передачи данных. Контекст постепенно обогащается по мере прохождения цепочки:
Такая модель позволяет строить сложные системы без дублирования логики.
Middleware в Iron формирует отдельный архитектурный слой, отвечающий за безопасность. Этот слой отделён от маршрутов и бизнес-логики, что позволяет централизовать:
Такое разделение делает систему предсказуемой и масштабируемой без изменения конечных обработчиков маршрутов.