Пропустить до содержимого

Промежуточное ПО

Промежуточное ПО(Middleware) позволяет перехватывать запросы и ответы и динамически внедрять дополнительное поведение каждый раз, когда страница или эндпоинт должны быть отрендерены. Этот рендеринг происходит во время сборки для всех предварительно отрендеренных страниц, а для страниц, отрисовываемых по требованию, - при запросе маршрута.

Промежуточное ПО также позволяет устанавливать и передавать специфическую для запроса информацию между эндпоинтами и страницами, изменяя объект locals, который доступен во всех компонентах Astro и API эндпоинтах. Этот объект доступен даже при запуске этого промежуточного ПО во время сборки.

  1. Создайте src/middleware.js|ts (В качестве альтернативы можно создать src/middleware/index.js|ts).

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

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

    src/components/Component.astro
    ---
    const data = Astro.locals;
    ---
    <h1>{data.title}</h1>
    <p>This {data.property} is from middleware.</p>

Объект context содержит информацию, которая будет доступна другому промежуточному ПО, маршрутам API и маршрутам .astro в процессе рендеринга.

Это необязательный аргумент, передаваемый в onRequest(), который может содержать объект locals, а также любые дополнительные свойства, которые будут переданы во время рендеринга. Например, объект context может содержать куки, используемые при аутентификации.

context.locals - это объект, которым можно манипулировать внутри промежуточного ПО.

Этот объект locals передается в процессе обработки запроса и доступен в качестве свойства для APIContext и AstroGlobal. Это позволяет обмениваться данными между промежуточным ПО, маршрутами API и страницами .astro. Это полезно для хранения специфических данных запроса, таких как данные пользователя, на всех этапах рендеринга.

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

src/middleware.js
export function onRequest ({ locals, request }, next) {
// перехват данных из запроса
// по желанию, измените свойства в `locals`
locals.user.name = "John Wick";
locals.welcomeTitle = () => {
return "Welcome back " + locals.user.name;
};
// верните ответ или результат вызова `next()`
return next();
};

Затем вы можете использовать эту информацию внутри любого файла .astro с помощью Astro.locals.

src/pages/orders.astro
---
const title = Astro.locals.welcomeTitle();
const orders = Array.from(Astro.locals.orders.entries());
---
<h1>{title}</h1>
<p>This {data.property} is from middleware.</p>
<ul>
{orders.map(order => {
return <li>{/* do something with each order */}</li>;
})}
</ul>

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

Пример: редактирование конфиденциальной информации

Заголовок раздела Пример: редактирование конфиденциальной информации

В примере ниже используется промежуточное ПО для замены слова “PRIVATE INFO” на слово “REDACTED”, что позволяет отображать измененный HTML на вашей странице:

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";
// `context` и `next` автоматически типизируются
export const onRequest = defineMiddleware((context, next) => {
});

В противном случае, если вы используете JsDoc для обеспечения безопасности типов, вы можете использовать MiddlewareHandler:

src/middleware.js
/**
* @type {import("astro").MiddlewareHandler}
*/
// `context` и `next` автоматически типизируются
export const onRequest = (context, next) => {
};

Чтобы типизировать информацию внутри Astro.locals, что дает вам автозаполнение внутри файлов .astro и кода промежуточного программного обеспечения, объявите глобальное пространство имен в файле env.d.ts:

src/env.d.ts
/// <reference types="astro/client" />
declare namespace App {
interface Locals {
user: {
name: string
},
welcomeTitle: () => string,
orders: Map<string, object>
}
}

Затем, внутри файла промежуточного ПО, вы можете воспользоваться преимуществами автозавершения и безопасности типов.

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

src/middleware.js
import { sequence } from "astro:middleware";
async function validation(_, next) {
console.log("validation request");
const response = await next();
console.log("validation response");
return response;
}
async function auth(_, next) {
console.log("auth request");
const response = await next();
console.log("auth response");
return response;
}
async function greeting(_, next) {
console.log("greeting request");
const response = await next();
console.log("greeting response");
return response;
}
export const onRequest = sequence(validation, auth, greeting);

Это приведет к следующему порядку в консоли:

Terminal window
validation request
auth request
greeting request
greeting response
auth response
validation response

Промежуточное ПО будет пытаться запустить все страницы по требованию, даже если подходящий маршрут не может быть найден. Это включает в себя стандартную (пустую) страницу 404 в Astro и любые пользовательские страницы 404. Однако решение о том, будет ли выполняться этот код, зависит от адаптера. Некоторые адаптеры могут выдавать вместо этого страницу ошибки, специфичную для конкретной платформы.

Промежуточное ПО также попытается запуститься перед выдачей страницы ошибки 500, включая пользовательскую страницу 500, если только ошибка сервера не произошла во время выполнения самого промежуточного ПО. Если ваше промежуточное ПО не будет успешно запущено, то у вас не будет доступа к Astro.locals для отображения вашей 500-страницы.