Middleware в Page.js представляют собой функции, которые выполняются до обработки основного маршрута и позволяют управлять поведением приложения на уровне маршрутизации. Middleware используется для таких задач, как проверка авторизации, логирование, модификация данных запроса или динамическая подгрузка ресурсов.
Каждая middleware-функция получает три параметра: ctx
(контекст маршрута), next (функция для передачи управления
следующей middleware) и иногда done (для завершения
цепочки, если необходимо прервать дальнейшую обработку).
function logger(ctx, next) {
console.log(`Переход на маршрут: ${ctx.path}`);
next();
}
Вызов next() обязателен для продолжения цепочки
middleware. Если его не вызвать, последующие middleware и обработчик
маршрута не будут выполнены.
Middleware можно подключать глобально ко всем маршрутам или к отдельным маршрутам.
Глобальная middleware:
page(logger); // применится ко всем маршрутам
page('/home', homePage);
page('/about', aboutPage);
page.start();
В этом примере функция logger будет вызываться при
каждом переходе по любому маршруту.
Middleware для конкретного маршрута:
page('/dashboard', authCheck, dashboardPage);
Здесь функция authCheck будет выполнена только при
переходе на /dashboard.
Page.js поддерживает использование нескольких middleware на одном маршруте. Они выполняются последовательно в порядке объявления.
page('/profile', authCheck, loadUserData, renderProfile);
function authCheck(ctx, next) {
if (!ctx.user) {
page.redirect('/login');
} else {
next();
}
}
function loadUserData(ctx, next) {
fetch(`/api/user/${ctx.user.id}`)
.then(res => res.json())
.then(data => {
ctx.userData = data;
next();
});
}
В этом примере цепочка middleware сначала проверяет авторизацию
пользователя, затем загружает данные, и только после этого вызывается
основной обработчик маршрута renderProfile.
Middleware часто выполняют асинхронные операции, например, запросы к
серверу. Важно корректно использовать next() после
завершения асинхронной операции, иначе маршрутизация будет
остановлена.
function fetchData(ctx, next) {
fetch('/api/items')
.then(response => response.json())
.then(data => {
ctx.items = data;
next();
})
.catch(err => console.error(err));
}
Если требуется прервать дальнейшее выполнение, можно просто не
вызывать next() или использовать
page.redirect() для перенаправления.
Глобальные middleware применяются ко всем маршрутам. Их удобно использовать для:
Локальные middleware привязаны к конкретным маршрутам. Их используют для:
function requireAuth(ctx, next) {
if (!ctx.user) {
page.redirect('/login');
} else {
next();
}
}
page('/settings', requireAuth, renderSettings);
page('/products/:id', loadProduct, renderProduct);
function loadProduct(ctx, next) {
const id = ctx.params.id;
fetch(`/api/products/${id}`)
.then(res => res.json())
.then(product => {
ctx.product = product;
next();
});
}
page((ctx, next) => {
console.log(`Переход на ${ctx.path} в ${new Date().toISOString()}`);
next();
});
Порядок объявления middleware имеет критическое значение:
page(fn).Если middleware не вызывает next(), цепочка
останавливается, и основной обработчик не выполняется.
В объекте ctx доступны следующие ключевые данные:
ctx.path — текущий путь маршрутаctx.params — объект с параметрами маршрутаctx.querystring — строка запроса после
?ctx.state — можно использовать для передачи данных
между middlewarefunction addTimestamp(ctx, next) {
ctx.state.timestamp = Date.now();
next();
}
Использование ctx.state позволяет middleware
обмениваться данными без глобальных переменных.
Middleware может полностью остановить выполнение маршрута:
function blockAccess(ctx, next) {
if (ctx.user.role !== 'admin') {
page.redirect('/not-authorized');
} else {
next();
}
}
В этом примере, если условие не выполнено, последующие middleware и
обработчик маршрута не вызовутся, а пользователь будет перенаправлен на
страницу /not-authorized.
ctx.state для передачи данных между
middleware, вместо глобальных переменных.Middleware в Page.js обеспечивает гибкий механизм управления маршрутизацией, позволяя выстраивать сложные цепочки действий до рендеринга страницы и управлять состоянием приложения в централизованном и предсказуемом виде.