Глобальные middleware

В библиотеке Navigo middleware — это функции, которые выполняются перед обработкой конкретного маршрута. Они позволяют выполнять общие действия для всех маршрутов, такие как проверка авторизации, логирование или подготовка данных. Глобальные middleware применяются ко всем маршрутам сразу и являются мощным инструментом для централизованного управления поведением приложения.


Подключение глобального middleware

Глобальные middleware в Navigo задаются через метод .hooks() при инициализации роутера или позже через router.hooks(). Основные события, на которые можно повесить middleware, это:

  • before — вызывается перед обработкой маршрута.
  • after — вызывается после обработки маршрута.

Пример подключения:

import Navigo from 'navigo';

const router = new Navigo('/', { hash: true });

router.hooks({
  before: (done, match) => {
    console.log('Проверка перед маршрутом:', match.url);
    done(); // продолжение маршрутизации
  },
  after: (match) => {
    console.log('Маршрут обработан:', match.url);
  }
});

Пояснения к коду:

  • done — функция, которую необходимо вызвать для продолжения навигации. Если она не вызывается, переход к маршруту блокируется.
  • match — объект, содержащий информацию о маршруте: url, params, queryString.

Использование before для авторизации

Одна из типичных задач глобального middleware — проверка доступа пользователя. Можно реализовать глобальную проверку перед каждым маршрутом:

router.hooks({
  before: (done, match) => {
    const userLoggedIn = Boolean(localStorage.getItem('token'));
    if (!userLoggedIn && match.url !== '/login') {
      router.navigate('/login');
    } else {
      done();
    }
  }
});

Ключевые моменты:

  • Если пользователь не авторизован, перенаправление выполняется через router.navigate().
  • Вызов done() разрешает продолжение маршрутизации.
  • Middleware срабатывает до любого конкретного маршрута, поэтому логика авторизации централизована.

Логирование и аналитика

Глобальные middleware удобно использовать для логирования и аналитики. Например, запись переходов на маршруты:

router.hooks({
  after: (match) => {
    console.log(`Пользователь перешел на ${match.url}`);
    sendAnalytics(match.url); // кастомная функция отправки данных
  }
});

Особенности:

  • Middleware after вызывается после того, как маршрут отработал.
  • Можно выполнять асинхронные действия, например отправку данных на сервер.
  • Так как middleware глобальные, они не дублируются для каждого маршрута.

Асинхронные глобальные middleware

before middleware может быть асинхронным. Это удобно для загрузки данных или проверки прав на сервере перед отображением страницы:

router.hooks({
  before: async (done, match) => {
    try {
      const hasAccess = await checkAccess(match.url); // проверка на сервере
      if (hasAccess) {
        done();
      } else {
        router.navigate('/403');
      }
    } catch (err) {
      console.error('Ошибка проверки доступа:', err);
      router.navigate('/error');
    }
  }
});

Особенности:

  • Middleware может содержать await для асинхронных операций.
  • Важно вызывать done() только после завершения всех проверок, иначе маршрутизация будет остановлена.
  • Ошибки можно обрабатывать локально, перенаправляя на страницы ошибок.

Цепочка глобальных middleware

Можно подключить несколько глобальных before или after функций. Они выполняются последовательно в порядке подключения:

router.hooks({
  before: [
    (done, match) => {
      console.log('Первый middleware');
      done();
    },
    (done, match) => {
      console.log('Второй middleware');
      done();
    }
  ]
});

Особенности:

  • Если один middleware не вызовет done(), последующие не будут выполнены.
  • Это позволяет строить цепочку проверок и условий для маршрутизации.

Доступ к объекту маршрута

В глобальных middleware объект match предоставляет всю информацию о маршруте:

{
  url: '/products/123',
  queryString: 'ref=homepage',
  params: { id: '123' },
  data: {}
}

Использование match позволяет:

  • Проверять параметры маршрута (match.params).
  • Анализировать URL (match.url).
  • Работать с query-параметрами (match.queryString).
  • Передавать данные между middleware через match.data.

Передача данных через match.data

Глобальные middleware могут сохранять данные для использования в маршрутах:

router.hooks({
  before: (done, match) => {
    match.data.startTime = Date.now();
    done();
  },
  after: (match) => {
    const duration = Date.now() - match.data.startTime;
    console.log(`Маршрут обработан за ${duration} мс`);
  }
});

Такой подход позволяет:

  • Измерять время обработки маршрутов.
  • Передавать промежуточные результаты между before и after.
  • Минимизировать глобальные переменные.

Особенности использования глобальных middleware

  1. Глобальный охват — middleware выполняются для всех маршрутов, включая динамические.
  2. Контроль потока — вызов done() решает, будет ли обработан маршрут.
  3. Асинхронность — middleware могут выполнять асинхронные операции без блокировки.
  4. Цепочка выполнения — порядок подключения имеет значение.
  5. Доступ к match.data — позволяет обмениваться данными между middleware и обработчиками маршрутов.

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