Глобальные middleware в библиотеке Page.js представляют собой функции-посредники, которые выполняются при каждом переходе по маршруту. Они позволяют централизованно обрабатывать повторяющиеся задачи: проверку авторизации, логирование, модификацию контекста запроса, загрузку данных и многое другое.
В отличие от middleware, привязанных к конкретным маршрутам, глобальные middleware применяются ко всем маршрутам без исключения, что делает их мощным инструментом для организации кросс-секционных аспектов приложения.
В основе лежит цепочка функций, каждая из которых получает два аргумента:
function middleware(ctx, next) {
// логика
next();
}
Глобальные middleware регистрируются через вызов page()
без указания пути:
page(middleware1);
page(middleware2);
Порядок регистрации определяет порядок выполнения.
Контекст передается через всю цепочку middleware и может изменяться на любом этапе.
Основные свойства:
ctx.path — текущий путьctx.params — параметры маршрутаctx.querystring — строка запросаctx.hash — хешctx.state — пользовательские данныеctx.handled — флаг обработкиПример модификации:
page((ctx, next) => {
ctx.startTime = Date.now();
next();
});
Глобальные middleware выполняются до middleware маршрута.
Пример:
page(globalMiddleware);
page('/user', routeMiddleware);
Порядок вызова:
Если зарегистрировано несколько глобальных middleware:
page(m1);
page(m2);
page('/test', handler);
Цепочка будет следующей:
m1 → m2 → handler
Вызов next() обязателен для продолжения цепочки:
page((ctx, next) => {
console.log('Перед');
next();
console.log('После');
});
Если next() не вызван, выполнение останавливается:
page((ctx, next) => {
if (!isAuthorized()) {
page.redirect('/login');
return;
}
next();
});
page((ctx, next) => {
if (!auth.isLoggedIn()) {
return page.redirect('/login');
}
next();
});
page((ctx, next) => {
console.log(`Переход: ${ctx.path}`);
next();
});
page((ctx, next) => {
const start = performance.now();
next();
const end = performance.now();
console.log(`Время выполнения: ${end - start}ms`);
});
page((ctx, next) => {
ctx.user = getCurrentUser();
next();
});
Page.js поддерживает асинхронные операции, но требует явного управления потоком.
page((ctx, next) => {
fetch('/api/data')
.then(res => res.json())
.then(data => {
ctx.data = data;
next();
});
});
page(async (ctx, next) => {
const res = await fetch('/api/data');
ctx.data = await res.json();
next();
});
Важно: next() должен вызываться вручную даже в
async-функциях.
Глобальные middleware можно комбинировать с локальными:
page(authMiddleware);
page('/dashboard',
loadDashboardData,
renderDashboard
);
Порядок выполнения:
Page.js не имеет встроенного механизма обработки ошибок middleware, поэтому используется ручной подход.
page((ctx, next) => {
try {
next();
} catch (err) {
console.error(err);
page.redirect('/error');
}
});
Для асинхронных операций:
page((ctx, next) => {
fetch('/api')
.then(() => next())
.catch(() => page.redirect('/error'));
});
Middleware может инициировать перенаправление:
page((ctx, next) => {
if (ctx.path === '/old') {
return page.redirect('/new');
}
next();
});
Глобальные middleware позволяют внедрять дополнительную логику без изменения самих маршрутов:
page((ctx, next) => {
ctx.isMobile = /mobile/i.test(navigator.userAgent);
next();
});
Теперь любой маршрут может использовать
ctx.isMobile.
Middleware удобно выносить в отдельные функции:
function logger(ctx, next) {
console.log(ctx.path);
next();
}
function auth(ctx, next) {
if (!user) return page.redirect('/login');
next();
}
page(logger);
page(auth);
Критически важно учитывать порядок:
page(auth);
page(logger);
В этом случае логирование произойдет после проверки авторизации.
Каждое middleware добавляет накладные расходы. При большом количестве:
Рекомендуется:
next())Глобальные middleware — основной способ расширения ctx:
page((ctx, next) => {
ctx.api = createApiClient();
next();
});
Это позволяет избежать глобальных переменных.
Сходства:
next()Отличия:
req/resТипичная структура:
// глобальные middleware
page(initApp);
page(auth);
page(logger);
page(loadUser);
// маршруты
page('/', homeHandler);
page('/profile', profileHandler);
Где:
initApp — базовая инициализацияauth — проверка доступаlogger — аналитикаloadUser — загрузка данных пользователяДля отладки цепочки middleware удобно добавлять временные логи:
page((ctx, next) => {
console.log('Middleware 1 start');
next();
console.log('Middleware 1 end');
});
Это помогает понять порядок выполнения.
1. Забыт вызов next()
page((ctx, next) => {
console.log('Лог');
// next() отсутствует
});
Результат: маршруты не выполняются.
2. Двойной вызов next()
page((ctx, next) => {
next();
next(); // ошибка
});
Приводит к непредсказуемому поведению.
3. Асинхронность без ожидания
page((ctx, next) => {
fetch('/api');
next(); // данные еще не загружены
});
Рекомендуется разделять middleware по назначению:
middlewares/auth.jsmiddlewares/logger.jsmiddlewares/data.jsИ подключать централизованно:
import auth from './middlewares/auth';
import logger from './middlewares/logger';
page(auth);
page(logger);
Page.js основан на History API, поэтому глобальные middleware срабатывают при:
page()Но не срабатывают при:
Глобальные middleware могут:
Важно соблюдать баланс между логикой и скоростью.
page((ctx, next) => {
console.log('Старт');
next();
});
page((ctx, next) => {
ctx.user = getUser();
next();
});
page('/dashboard', (ctx) => {
console.log('Рендер dashboard', ctx.user);
});
Цепочка:
Старт → загрузка пользователя → рендер
Глобальные middleware формируют фундамент маршрутизации в Page.js, обеспечивая единый поток обработки запросов и централизованное управление логикой приложения.