Понятие middleware в Universal Router

В Universal Router middleware выступает ключевым механизмом для промежуточной обработки маршрутов, позволяя внедрять дополнительные шаги до или после основной логики маршрута. Middleware выполняет функции фильтрации, проверки прав доступа, логирования, модификации контекста запроса или динамического перенаправления.

Основы работы middleware

В Universal Router middleware реализуется через функцию, которая получает два основных параметра:

  1. context — объект контекста маршрута, содержащий информацию о текущем пути (pathname), параметрах (params), предыдущем состоянии и дополнительных данных, переданных при вызове router.resolve(context).
  2. next — функция, запускающая следующий middleware или сам маршрут. Вызов await next() позволяет передать управление дальше, а отсутствие вызова effectively останавливает цепочку, предотвращая переход к целевому маршруту.

Простейший пример middleware:

const authMiddleware = async (context, next) => {
  if (!context.user) {
    return '/login'; // перенаправление на страницу входа
  }
  return next(); // передача управления следующему middleware или маршруту
};

Ключевой момент: middleware может возвращать результат, который станет итоговым значением вызова router.resolve(). Это может быть строка с путем перенаправления, объект с данными или значение, которое возвращает конечный обработчик маршрута.

Подключение middleware к маршрутам

Middleware может применяться глобально для всех маршрутов или локально для отдельных маршрутов.

Глобальное подключение:

import UniversalRouter from 'universal-router';

const routes = [
  { path: '/', action: () => 'Главная' },
  { path: '/dashboard', action: () => 'Панель управления' },
];

const router = new UniversalRouter(routes, {
  context: {},
  resolveRoute(context, params) {
    // встроенный вызов middleware
  },
  middleware: [authMiddleware], // массив middleware
});

Локальное подключение к маршруту:

const routes = [
  {
    path: '/admin',
    action: () => 'Админка',
    middleware: [authMiddleware]
  }
];

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

Цепочка вызова и управление потоком

Middleware в Universal Router формирует цепочку, где каждая функция может:

  • модифицировать контекст (context) для последующих middleware и маршрута;
  • завершить обработку и вернуть результат, минуя следующие middleware;
  • вызвать await next() для передачи управления дальше.

Пример модификации контекста:

const addTimestamp = async (context, next) => {
  context.timestamp = Date.now();
  return next();
};

const routes = [
  { path: '/time', action: (context) => `Время запроса: ${context.timestamp}` }
];

const router = new UniversalRouter(routes, { middleware: [addTimestamp] });

Middleware для перенаправлений и ошибок

Middleware удобно использовать для реализации логики перенаправлений и обработки ошибок.

Пример перенаправления:

const redirectMiddleware = async (context, next) => {
  if (context.pathname === '/old-page') {
    return '/new-page';
  }
  return next();
};

Пример обработки ошибок:

const errorHandlingMiddleware = async (context, next) => {
  try {
    return await next();
  } catch (error) {
    console.error('Ошибка маршрутизации:', error);
    return '/error';
  }
};

Совмещение нескольких middleware

Universal Router позволяет объединять несколько middleware в цепочку, где порядок их подключения критичен:

const router = new UniversalRouter(routes, {
  middleware: [
    errorHandlingMiddleware,
    authMiddleware,
    addTimestamp
  ]
});

В этом примере сначала обрабатываются ошибки, затем проверка авторизации и только после этого добавляется метка времени. Любой middleware может прервать цепочку или изменить результат.

Рекомендации по использованию

  • Middleware должен быть асинхронным, чтобы поддерживать await next();
  • Возвращаемое значение middleware должно быть консистентным с тем, что ожидает конечный маршрут;
  • Минимизировать побочные эффекты, чтобы один middleware не ломал работу других;
  • Использовать глобальные middleware для общих правил (логирование, авторизация), а локальные — для специфичных маршрутов.

Middleware в Universal Router обеспечивает гибкий способ управлять маршрутизацией, создавать динамические проверки и улучшать архитектуру приложения, позволяя отделить бизнес-логику маршрутов от вспомогательных процессов.