В Page.js middleware представляет собой функцию,
которая выполняется перед обработчиком маршрута и получает объект
контекста, а также функцию next для передачи управления
следующему middleware или маршруту. Middleware позволяет централизованно
обрабатывать повторяющуюся логику: проверку авторизации, загрузку
данных, ведение логов, а также модификацию контекста перед передачей его
конечному обработчику.
Page.js поддерживает концепцию групп маршрутов, когда несколько маршрутов объединяются под одним контекстом или префиксом, что позволяет применять один middleware ко всем маршрутам группы. Это особенно удобно при построении SPA (Single Page Application) с несколькими секциями, требующими одинаковой предобработки.
Простейший способ реализовать группу маршрутов — использовать функцию обёртку:
function group(basePath, middleware, routes) {
routes.forEach(route => {
page(basePath + route.path, middleware, route.handler);
});
}
Пример использования:
group('/admin', requireAuth, [
{ path: '/dashboard', handler: adminDashboard },
{ path: '/users', handler: manageUsers },
{ path: '/settings', handler: adminSettings }
]);
Здесь requireAuth — middleware, проверяющий права
доступа. Он выполняется перед каждым маршрутом
/admin/*.
Page.js позволяет объединять несколько middleware в цепочку. Каждый
middleware получает объект ctx и функцию next.
Цепочка выполняется последовательно: первый middleware вызывает
next(), управление передается следующему, и так далее, пока
не будет вызван конечный обработчик маршрута.
Пример цепочки:
function logMiddleware(ctx, next) {
console.log(`Переход на маршрут: ${ctx.path}`);
next();
}
function loadUserMiddleware(ctx, next) {
ctx.user = { name: 'Alice', role: 'admin' };
next();
}
page('/profile', logMiddleware, loadUserMiddleware, showProfile);
Преимущество группового подхода заключается в возможности применить цепочку middleware ко всей группе маршрутов:
group('/account', [logMiddleware, loadUserMiddleware], [
{ path: '/settings', handler: accountSettings },
{ path: '/history', handler: accountHistory }
]);
В этом случае для маршрутов /account/settings и
/account/history будут последовательно вызваны оба
middleware.
Middleware для группы маршрутов корректно работает с динамическими сегментами URL, что позволяет использовать универсальные проверки и загрузку данных.
Пример:
function loadArticle(ctx, next) {
const articleId = ctx.params.id;
fetch(`/api/articles/${articleId}`)
.then(res => res.json())
.then(data => {
ctx.article = data;
next();
});
}
group('/blog', loadArticle, [
{ path: '/:id', handler: showArticle },
{ path: '/:id/edit', handler: editArticle }
]);
В данном примере middleware loadArticle срабатывает для
всех маршрутов /blog/:id*, загружая данные статьи и
добавляя их в контекст.
Ошибки в middleware можно обрабатывать централизованно. Для этого
достаточно обернуть асинхронные операции в try/catch и при
ошибке перенаправить на страницу ошибки или вызвать специальный
middleware для обработки ошибок:
function safeMiddleware(ctx, next) {
try {
next();
} catch (err) {
console.error('Ошибка в middleware:', err);
page('/error');
}
}
ctx. Любая
информация, необходимая обработчику маршрута, должна сохраняться в
ctx, а не в глобальных переменных.function authMiddleware(ctx, next) {
if (!ctx.user) {
page('/login');
} else {
next();
}
}
function analyticsMiddleware(ctx, next) {
sendAnalytics(ctx.path);
next();
}
group('/dashboard', [authMiddleware, analyticsMiddleware], [
{ path: '/', handler: dashboardHome },
{ path: '/reports', handler: dashboardReports },
{ path: '/settings', handler: dashboardSettings }
]);
В этом примере для всех маршрутов /dashboard/*
выполняется проверка авторизации и отправка аналитики, после чего
вызывается соответствующий обработчик страницы.