Перейти к содержимому

Мидлвар

Мидлвар (Middleware) позволяет перехватывать запросы и ответы и динамически внедрять логику перед рендерингом каждой страницы или эндпойнта. Для предварительно отрендеренных страниц это происходит во время сборки, а для страниц по запросу — в момент обращения к маршруту.

Мидлвар также позволяет обмениваться данными между эндпойнтами и страницами через объект locals, доступный во всех компонентах Astro и API-маршрутах.

  1. Создайте файл src/middleware.js|ts (или src/middleware/index.js|ts).

  2. Экспортируйте функцию onRequest(), принимающую объект context и функцию next(). Это не должен быть экспорт по умолчанию (default export).

    src/middleware.js
    export function onRequest (context, next) {
    // Перехват данных запроса
    // Можно изменить свойства в `locals`
    context.locals.title = "Новый заголовок";
    // Возвращаем Response или результат вызова `next()`
    return next();
    };
  3. В любом .astro файле получите доступ к данным через Astro.locals.

    src/components/Component.astro
    ---
    const data = Astro.locals;
    ---
    <h1>{data.title}</h1>

Объект context содержит информацию, доступную другим мидлварам и маршрутам в процессе рендеринга. Он включает в себя объект locals, а также может содержать куки, заголовки и другие параметры запроса.

context.locals — это объект для хранения данных в рамках одного жизненного цикла запроса.

Этот объект передается через весь процесс обработки и доступен как свойство в APIContext и AstroGlobal. Это удобно для хранения данных пользователя или результатов авторизации.

Вы можете хранить в locals данные любого типа: строки, числа, функции и даже сложные объекты.

src/middleware.js
export function onRequest (context, next) {
context.locals.user = { name: "Джон Уик" };
context.locals.welcomeTitle = () => {
return "С возвращением, " + context.locals.user.name;
};
return next();
};

Использование в .astro файле:

src/pages/orders.astro
---
const title = Astro.locals.welcomeTitle();
---
<h1>{title}</h1>

locals существует только в рамках обработки одного маршрута. Данные, которые должны сохраняться между разными посещениями страниц, нужно хранить в куках или базе данных.

Мидлвар можно использовать для модификации итогового HTML-кода ответа. Пример замены текста «PRIVATE INFO» на слово «REDACTED»:

src/middleware.js
export const onRequest = async (context, next) => {
const response = await next();
const html = await response.text();
const redactedHtml = html.replaceAll("PRIVATE INFO", "REDACTED");
return new Response(redactedHtml, {
status: 200,
headers: response.headers
});
};

Для обеспечения типобезопасности используйте функцию defineMiddleware():

src/middleware.ts
import { defineMiddleware } from "astro:middleware";
export const onRequest = defineMiddleware((context, next) => {
// `context` и `next` типизированы автоматически
});

Для расширения типов в Astro.locals добавьте описание интерфейса в файл env.d.ts:

src/env.d.ts
declare namespace App {
interface Locals {
user: { id: number; name: string };
welcomeTitle: () => string;
}
}

Несколько мидлваров можно объединить в заданном порядке с помощью sequence():

src/middleware.js
import { sequence } from "astro:middleware";
async function auth(context, next) {
// логика авторизации
return next();
}
async function analytics(context, next) {
// логика аналитики
return next();
}
export const onRequest = sequence(auth, analytics);

Добавлено в: astro@4.13.0

Метод context.rewrite() позволяет отобразить содержимое другой страницы без изменения URL в браузере.

src/middleware.js
export function onRequest (context, next) {
if (!isLoggedIn(context)) {
// Перезаписываем запрос на страницу входа
return context.rewrite("/login");
}
return next();
};

Вы также можете передать путь прямо в функцию next(): return next("/login"). Это обновит Request «на лету» для следующих мидлваров в цепочке без перезапуска всего процесса рендеринга.

Мидлвар пытается запуститься для всех страниц по запросу, даже если маршрут не найден (для 404). Однако поведение зависит от адаптера. Мидлвар также запускается перед отображением страницы ошибки 500, если только сама ошибка не произошла внутри кода мидлвара.