Создание промежуточных обработчиков

Промежуточные обработчики (middlewares) в библиотеке Navigo позволяют внедрять дополнительную логику между определением маршрута и его выполнением. Они используются для проверки прав доступа, предзагрузки данных, логирования или выполнения любых других действий до того, как основной обработчик маршрута будет вызван.

В Navigo промежуточные обработчики реализуются с помощью функции before, которая принимает массив функций или одну функцию. Каждая функция получает объект done, который нужно вызвать для продолжения маршрута, и объект match, содержащий параметры маршрута.

router.on('/dashboard', () => {
  console.log('Главная панель');
}).before((done, match) => {
  if (!user.isLoggedIn()) {
    console.log('Пользователь не авторизован');
  } else {
    done();
  }
});

В этом примере функция before проверяет авторизацию пользователя. Если пользователь не авторизован, маршрут не выполняется, иначе вызывается done() и обработчик маршрута срабатывает.


Структура промежуточного обработчика

Промежуточный обработчик в Navigo имеет следующую сигнатуру:

function middleware(done, match) { ... }
  • done — функция, которая запускает выполнение основного маршрута. Если не вызвать done(), маршрут останется заблокирован.

  • match — объект с информацией о маршруте:

    • match.url — текущий URL без хеша.
    • match.route — объект маршрута, который соответствует URL.
    • match.data — данные маршрута, включая параметры URL.

Пример использования параметров маршрута:

router.on('/user/:id', (params) => {
  console.log('ID пользователя:', params.id);
}).before((done, match) => {
  console.log('Проверяем параметры маршрута:', match.data);
  done();
});

Множественные промежуточные обработчики

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

router.on('/settings', () => {
  console.log('Настройки загружены');
}).before([
  (done, match) => {
    console.log('Проверка авторизации');
    if (user.isLoggedIn()) done();
  },
  (done, match) => {
    console.log('Логирование перехода на маршрут');
    done();
  }
]);

В этом примере сначала выполняется проверка авторизации, затем логирование. Если первый обработчик не вызовет done(), второй не выполнится, и основной обработчик маршрута не сработает.


Асинхронные промежуточные обработчики

Промежуточные обработчики могут содержать асинхронную логику, например, запросы к серверу. Для этого необходимо вызвать done() после завершения всех асинхронных операций.

router.on('/profile', () => {
  console.log('Профиль пользователя отображен');
}).before((done, match) => {
  fetch('/api/user/check')
    .then(response => response.json())
    .then(data => {
      if (data.allowed) {
        done();
      } else {
        console.log('Доступ запрещен');
      }
    });
});

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


Глобальные промежуточные обработчики

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

router.hooks({
  before(done, match) {
    console.log('Переход на маршрут:', match.url);
    done();
  }
});

Глобальный обработчик выполняется перед любым локальным before, что позволяет централизованно контролировать поведение приложения.


Советы по использованию промежуточных обработчиков

  • Всегда вызывать done(), если маршрут должен продолжить выполнение.
  • Для асинхронных операций использовать Promise или fetch, но убедиться, что done() вызывается после завершения всех операций.
  • Использовать глобальные обработчики для общих проверок и локальные для маршрутов с уникальной логикой.
  • Множественные обработчики позволяют разделять ответственность: один для авторизации, другой для логирования, третий — для подготовки данных.

Пример комплексного использования

router.on('/dashboard/:section', (params) => {
  console.log('Раздел:', params.section);
}).before([
  (done, match) => {
    if (!user.isLoggedIn()) {
      console.log('Неавторизованный доступ к разделу:', match.data.section);
    } else {
      done();
    }
  },
  async (done, match) => {
    try {
      const data = await fetch(`/api/section/${match.data.section}`).then(res => res.json());
      console.log('Данные раздела загружены', data);
      done();
    } catch (err) {
      console.error('Ошибка загрузки данных:', err);
    }
  }
]);

router.hooks({
  before(done, match) {
    console.log('Глобальная проверка маршрута:', match.url);
    done();
  }
});

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