Концепция middleware в Fresh

Fresh — это современный фреймворк для разработки веб-приложений на JavaScript и TypeScript, ориентированный на серверный рендеринг с минимальным объемом клиентского кода. Одной из ключевых концепций, обеспечивающих гибкость и расширяемость приложений в Fresh, является использование middleware.

Middleware в Fresh представляет собой функции промежуточной обработки запросов и ответов, которые выполняются между получением HTTP-запроса и генерацией окончательного ответа сервером. Они позволяют внедрять повторно используемую логику, управлять авторизацией, логированием, обработкой ошибок и другими аспектами, не вмешиваясь напрямую в бизнес-логику маршрутов.


Структура middleware

Middleware в Fresh строится на простом принципе: каждая функция получает два основных параметра:

export async function middleware(req: Request, next: () => Promise<Response>): Promise<Response> {
  // Логика до передачи запроса дальше
  const response = await next(); 
  // Логика после обработки запроса
  return response;
}
  • req — объект запроса Request, содержащий все данные HTTP-запроса.
  • next — функция, вызывающая следующий middleware или маршрут. Возвращает Promise<Response>, что обеспечивает асинхронность.

Ключевой момент: middleware может модифицировать запрос, блокировать его, перенаправлять или изменять ответ, возвращаемый клиенту.


Применение middleware

Middleware в Fresh может использоваться для следующих целей:

  1. Аутентификация и авторизация Прежде чем запрос попадет на обработчик маршрута, можно проверить токен пользователя или права доступа.

    export async function middleware(req: Request, next: () => Promise<Response>) {
      const token = req.headers.get("Authorization");
      if (!token || token !== "secret-token") {
        return new Response("Unauthorized", { status: 401 });
      }
      return next();
    }
  2. Логирование запросов Middleware позволяет собирать статистику и вести логи без изменения кода обработчиков.

    export async function middleware(req: Request, next: () => Promise<Response>) {
      console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
      const response = await next();
      console.log(`Response status: ${response.status}`);
      return response;
    }
  3. Обработка ошибок Ошибки, возникающие в маршрутах, можно перехватывать и обрабатывать централизованно.

    export async function middleware(req: Request, next: () => Promise<Response>) {
      try {
        return await next();
      } catch (err) {
        console.error("Ошибка запроса:", err);
        return new Response("Internal Server Error", { status: 500 });
      }
    }
  4. Кэширование и модификация ответа Middleware может изменять заголовки ответа, добавлять кеширование или модифицировать тело.

    export async function middleware(req: Request, next: () => Promise<Response>) {
      const response = await next();
      response.headers.set("Cache-Control", "max-age=3600");
      return response;
    }

Регистрация middleware

В Fresh middleware может быть глобальным или локальным для маршрута.

  • Глобальный middleware применяется ко всем маршрутам и указывается в файле main.ts или routes/_middleware.ts. Это удобно для авторизации, логирования или обработки ошибок на уровне всего приложения.

  • Локальный middleware размещается рядом с конкретным маршрутом, например routes/dashboard/_middleware.ts, и действует только для этого маршрута и его вложенных маршрутов.

Порядок выполнения middleware соответствует вложенности файловой структуры: сначала выполняются глобальные middleware, затем локальные, начиная с верхнего уровня к нижнему.


Асинхронность и цепочки middleware

Middleware в Fresh построен на цепочках. Каждый middleware может вызывать await next(), передавая управление следующей функции. Это позволяет строить сложные последовательности обработки, где результат одного middleware может влиять на поведение следующих.

Важно помнить, что необязательный вызов next() позволяет полностью прерывать обработку запроса, например, при отказе в доступе или при возвращении кэша.


Ограничения и особенности

  • Middleware в Fresh всегда асинхронные, что обеспечивает совместимость с промисами и асинхронными операциями, такими как запросы к базе данных.
  • Middleware не должно напрямую рендерить страницы; его задача — подготовка запроса и ответа. Рендеринг выполняется на уровне маршрутов или компонентов.
  • Рекомендуется использовать middleware для задач, которые повторяются во многих местах приложения, чтобы не дублировать код.

Вывод

Middleware в Fresh — это мощный инструмент управления потоком запросов и ответов. Он позволяет централизованно внедрять логику безопасности, логирования, кэширования и обработки ошибок, сохраняя при этом чистоту и модульность кода. Правильная организация middleware обеспечивает гибкость, повторное использование и масштабируемость приложений.