Fresh — серверный фреймворк для Deno, построенный вокруг HTTP-запросов и изоляции логики. Middleware в Fresh представляет собой функции-перехватчики, которые оборачивают обработку запроса и позволяют вмешиваться в жизненный цикл до или после выполнения маршрута.
Базовая сигнатура middleware:
import { MiddlewareHandlerContext } from "$fresh/server.ts";
export async function handler(
req: Request,
ctx: MiddlewareHandlerContext,
) {
return await ctx.next();
}
Middleware получает доступ к объекту Request, контексту
запроса и управляет тем, будет ли вызван следующий обработчик. Это
делает middleware центральным механизмом для аутентификации,
логирования, модификации заголовков, управления доступом и других
поперечных задач.
Условное применение middleware — это избирательное выполнение логики middleware в зависимости от контекста запроса: пути, метода, заголовков, состояния пользователя, окружения или любых других факторов.
В Fresh middleware по умолчанию применяется глобально или на уровне маршрутов, но внутри него всегда доступна возможность явно управлять логикой исполнения. Это принципиально отличается от фреймворков, где middleware жестко привязан к маршрутам.
Ключевая идея: middleware вызывается всегда, но его поведение может быть условным.
Самый распространённый сценарий — выполнение middleware только для определённых URL.
export async function handler(
req: Request,
ctx: MiddlewareHandlerContext,
) {
const url = new URL(req.url);
if (!url.pathname.startsWith("/admin")) {
return await ctx.next();
}
// логика только для /admin
}
Такой подход позволяет централизовать защиту административных
маршрутов без дублирования кода. Важно, что ctx.next()
вызывается явно — отсутствие вызова полностью прерывает цепочку.
Fresh middleware часто используется для ограничения действий по методу запроса.
if (req.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
Комбинация метода и пути позволяет точно контролировать поведение API, не смешивая валидацию с бизнес-логикой маршрута.
Условная проверка прав — один из самых показательных примеров.
const token = req.headers.get("authorization");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
При этом возможно более тонкое управление:
if (url.pathname.startsWith("/api/private")) {
// строгая проверка
}
Fresh позволяет передавать данные между middleware и обработчиком
маршрута через ctx.state.
ctx.state.user = user;
Условность может быть построена на основе уже установленного состояния:
if (!ctx.state.user?.isAdmin) {
return new Response("Forbidden", { status: 403 });
}
Это позволяет строить цепочки middleware, где каждый последующий зависит от результатов предыдущего.
Middleware может не только решать, пропускать ли запрос дальше, но и модифицировать ответ — также по условию.
const res = await ctx.next();
if (url.pathname.startsWith("/api")) {
res.headers.set("Cache-Control", "no-store");
}
return res;
Таким образом, одни и те же маршруты могут вести себя по-разному в зависимости от окружения или назначения.
Часто middleware должно работать только в режиме разработки или только в продакшене.
if (Deno.env.get("ENV") !== "production") {
console.log(req.method, req.url);
}
Это особенно полезно для логирования, отладки, метрик и экспериментальных функций.
На практике условия редко бывают одиночными. Обычно используется комбинация факторов:
if (
req.method === "POST" &&
url.pathname.startsWith("/api") &&
ctx.state.user
) {
// специфичная логика
}
Важно поддерживать читаемость: сложные условия лучше выносить в отдельные функции-предикаты.
Хотя Fresh допускает размещение всей логики в одном middleware, условное применение часто сочетается с архитектурным разделением:
Каждый из них содержит собственные условия, что упрощает сопровождение и тестирование.
Middleware может завершить обработку запроса досрочно, не вызывая
ctx.next(). Это осознанный инструмент управления
потоком.
if (blocked) {
return new Response("Blocked", { status: 403 });
}
При условном применении это особенно важно: отсутствие явного
return ctx.next() должно быть результатом логического
решения, а не побочным эффектом.
Условное middleware не заменяет маршруты. Маршруты отвечают за структуру приложения, middleware — за поперечные аспекты. Условность позволяет сохранить middleware универсальным, не привязывая его жестко к файловой системе маршрутов Fresh.
return ctx.next() в ветке условия;Правильно реализованное условное middleware остаётся тонким слоем контроля, а не центром приложения.
В Fresh условное применение middleware — это не workaround, а основной паттерн. Он позволяет:
При правильном использовании middleware становится декларативным механизмом политики, а не процедурной логикой обработки запроса.