Глобальный обработчик ошибок

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


Принцип работы

В основе Universal Router лежит функция resolve, которая принимает путь и возвращает результат выполнения соответствующего маршрута. Любое исключение, выброшенное в action маршрута, передаётся наверх по цепочке промисов. Для централизованной обработки этих ошибок можно использовать глобальный обработчик, задаваемый при создании экземпляра маршрутизатора:

import UniversalRouter from 'universal-router';

const routes = [
  { path: '/', action: () => 'Главная страница' },
  { path: '/about', action: () => { throw new Error('Ошибка при загрузке /about'); } },
];

const router = new UniversalRouter(routes, {
  resolveRoute(context, params) {
    try {
      return UniversalRouter.resolve.call(this, context, params);
    } catch (err) {
      return handleGlobalError(err, context, params);
    }
  }
});

function handleGlobalError(error, context, params) {
  console.error('Глобальная ошибка маршрута:', error.message);
  return 'Страница с ошибкой';
}

В этом примере функция resolveRoute выступает в роли обёртки над стандартным методом resolve, перехватывая все ошибки и передавая их в handleGlobalError. Это позволяет централизованно логировать ошибки, показывать пользователю страницу с сообщением об ошибке или выполнять другие действия.


Использование try/catch в action

Каждый маршрут может содержать асинхронные действия, и ошибки могут возникать как синхронно, так и асинхронно. Universal Router поддерживает промисы, поэтому обработка ошибок через try/catch должна учитывать асинхронность:

const routes = [
  {
    path: '/data',
    async action() {
      try {
        const response = await fetch('/api/data');
        if (!response.ok) throw new Error('Ошибка при загрузке данных');
        return await response.json();
      } catch (err) {
        throw err; // ошибка будет перехвачена глобальным обработчиком
      }
    }
  }
];

Даже если ошибка выбрасывается внутри асинхронной функции, глобальный обработчик, описанный выше, сможет её перехватить.


Настройка отдельного обработчика ошибок для конкретного маршрута

Иногда требуется специфическая обработка ошибок на уровне отдельного маршрута, при этом глобальный обработчик остаётся «запасным»:

const routes = [
  {
    path: '/profile',
    async action() {
      try {
        return await fetchUserProfile();
      } catch (err) {
        console.warn('Ошибка загрузки профиля, возвращаем дефолтные данные');
        return { name: 'Гость' };
      }
    }
  }
];

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


Асинхронные глобальные обработчики

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

async function handleGlobalError(error, context) {
  await sendErrorLogToServer(error, context.path);
  return { redirect: '/error' };
}

resolve корректно обработает промис, возвращённый обработчиком, и можно использовать результат для дальнейшей логики маршрутизации.


Контекст ошибки

Universal Router передаёт в обработчик ошибки контекст маршрута, что позволяет получать информацию о текущем пути, параметрах и родительских маршрутах:

function handleGlobalError(error, context) {
  console.error(`Ошибка на пути ${context.path}`);
  console.error('Параметры:', context.params);
  return 'Произошла ошибка';
}

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


Паттерны применения

  1. Логирование ошибок: все ошибки маршрутов отправляются в централизованную систему логирования.
  2. Пользовательские страницы ошибок: можно возвращать специальный компонент или HTML для отображения пользователю.
  3. Фоллбэк данные: в случае ошибки можно возвращать дефолтные данные, чтобы приложение продолжало работу.
  4. Асинхронные действия при ошибках: отправка данных на сервер, аналитика или автоматическая переадресация.

Рекомендации по проектированию

  • Всегда обеспечивать глобальный обработчик для предотвращения «падений» приложения.
  • Не использовать только локальные try/catch, так как часть ошибок может быть пропущена.
  • Для асинхронных маршрутов глобальный обработчик должен поддерживать промисы.
  • Использовать контекст маршрута для точной идентификации проблемного пути и параметров.

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