Universal Router — это гибкая библиотека для маршрутизации в JavaScript, которая позволяет создавать как простые, так и сложные маршруты с поддержкой вложенных структур и динамических сегментов. Один из ключевых аспектов построения маршрутизатора — корректная обработка ситуации, когда запрошенный путь не соответствует ни одному определённому маршруту. Это стандартная ситуация «404 Not Found».
В Universal Router обработка «страниц не найдено» реализуется с
помощью функции resolve или через маршруты, где ключевой
момент — отсутствие совпадений. Обычно для этого создаётся
маршрут-заглушка, который находится в конце массива
маршрутов. Такой маршрут срабатывает, когда ни один предыдущий маршрут
не подошёл.
Пример базового определения маршрута 404:
import UniversalRouter from 'universal-router';
const routes = [
{ path: '/', action: () => 'Главная страница' },
{ path: '/about', action: () => 'О нас' },
{
path: '(.*)', // Любой путь, который не был пойман выше
action: () => {
return 'Страница не найдена';
}
}
];
const router = new UniversalRouter(routes);
router.resolve('/non-existent').then(console.log); // Страница не найдена
Ключевые моменты:
(.*) позволяет
поймать любой путь, не сопоставленный с предыдущими маршрутами.action возвращает контент или объект, который
затем используется приложением для отображения ошибки.Маршрут 404 можно расширить, чтобы возвращать объект с кодом состояния HTTP, что удобно для серверного рендеринга:
const routes = [
{ path: '/', action: () => ({ status: 200, body: 'Главная' }) },
{ path: '/about', action: () => ({ status: 200, body: 'О нас' }) },
{
path: '(.*)',
action: () => ({ status: 404, body: 'Страница не найдена' })
}
];
async function handleRequest(path) {
const result = await router.resolve(path);
console.log(result.status); // 404
console.log(result.body); // Страница не найдена
}
handleRequest('/invalid');
Такой подход позволяет унифицировать обработку ошибок как на клиенте, так и на сервере, возвращая корректный HTTP-статус и тело ответа.
В сложных приложениях часто используются вложенные маршруты. В этом случае обработка 404 может быть как глобальной, так и локальной для конкретного сегмента.
Пример с вложенными маршрутами:
const routes = [
{
path: '/',
action: () => 'Главная',
children: [
{ path: 'dashboard', action: () => 'Панель управления' },
{
path: '(.*)',
action: () => 'Раздел не найден'
}
]
},
{
path: '(.*)',
action: () => 'Страница не найдена'
}
];
Особенности:
children: [{ path: '(.*)', ... }])
срабатывает для путей внутри родительского маршрута.context.next() для кастомного поведенияUniversal Router предоставляет возможность вызывать
context.next() в action, что позволяет
передавать обработку на следующий маршрут, если текущий маршрут не
подходит. Это полезно для реализации 404 через цепочку маршрутов:
const routes = [
{ path: '/', action: () => 'Главная' },
{ path: '/about', action: () => 'О нас' },
{
path: '/special',
action: async (context) => {
if (!context.userHasAccess) {
return context.next(); // Передаём управление следующему маршруту
}
return 'Специальная страница';
}
},
{
path: '(.*)',
action: () => 'Страница не найдена'
}
];
Преимущества:
Для динамических маршрутов важно предусматривать fallback на 404, если данные для страницы не найдены:
const routes = [
{ path: '/user/:id', action: async ({ params }) => {
const user = await getUser(params.id);
if (!user) return 'Пользователь не найден';
return `Профиль ${user.name}`;
}
},
{ path: '(.*)', action: () => 'Страница не найдена' }
];
/user/:id.status и
body для корректного HTTP-ответа.context.next(), чтобы
цепочка маршрутов могла корректно передавать управление.Эти подходы обеспечивают предсказуемое поведение приложения при неопределённых маршрутах и позволяют гибко управлять ошибками на уровне отдельных секций и глобально.