Aller au contenu

Le Middleware

Middleware vous permet d’intercepter les demandes et les réponses et d’injecter des comportements de manière dynamique chaque fois qu’une page ou un point de terminaison est sur le point d’être rendu. Ce rendu a lieu au moment de la construction pour toutes les pages pré-rendues, mais il a lieu lorsque la route est demandée pour les pages rendues à la demande, rendant disponible des fonctionnalités SSR supplémentaires telles que les cookies et les en-têtes.

Le middleware vous permet également de définir et de partager des informations spécifiques aux requêtes entre les points de terminaison et les pages en modifiant un objet locals disponible dans tous les composants Astro et les points de terminaison de l’API. Cet objet est disponible même lorsque ce middleware s’exécute au moment de la construction.

  1. Créez src/middleware.js|ts (Alternativement, vous pouvez créer src/middleware/index.js|ts.)

  2. Dans ce fichier, exportez une fonction onRequest() à laquelle on peut passer un objet context et une fonction next(). Il ne doit pas s’agir d’une exportation par défaut.

    src/middleware.js
    export function onRequest (context, next) {
    // intercepter les données d'une requête
    // optionnellement, modifie la propriété dans `locals`
    context.locals.title = "Nouveau titre";
    // renvoie une Réponse ou le résultat de l'appel à `next()`
    return next();
    };
  3. Dans n’importe quel fichier .astro, accédez aux données de réponse en utilisant Astro.locals.

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

L’objet context inclut des informations à mettre à disposition d’autres middleware, routes API et routes .astro pendant le processus de rendu.

C’est un argument optionnel passé à onRequest() qui peut contenir l’objet locals ainsi que toutes les propriétés additionnelles à partager pendant le rendu.Par exemple, l’objet context peut inclure les cookies utilisés pour l’authentification.

Stocker des données dans context.locals

Titre de la section Stocker des données dans context.locals

context.locals est un objet pouvant être manipulé dans le middleware.

Cet objet locals est transmis à travers le processus de traitement des requêtes et est disponible en tant que propriété pour APIContext et AstroGlobal. Cela permet de partager des données entre les middlewares, les routes API et les pages .astro. Ceci est utile pour stocker des données spécifiques à une requête, telles que les données de l’utilisateur, à travers l’étape de rendu.

Vous pouvez stocker n’importe quel type de données dans locals : des chaînes, des nombres, et même des types de données complexes tels que des fonctions et des cartes.

src/middleware.js
export function onRequest (context, next) {
// intercepter les données de réponse d'une requête
// optionnellement, modifie la propriété dans `locals`
context.locals.user.name = "John Wick";
context.locals.welcomeTitle = () => {
return "Welcome back " + locals.user.name;
};
// renvoie une Réponse ou le résultat de l'appel à `next()`
return next();
};

Vous pouvez ensuite utiliser ces informations dans n’importe quel fichier .astro avec Astro.locals.

src/pages/orders.astro
---
const title = Astro.locals.welcomeTitle();
const orders = Array.from(Astro.locals.orders.entries());
---
<h1>{title}</h1>
<p>Cette {data.property} provient du middleware.</p>
<ul>
{orders.map(order => {
return <li>{/* faire quelque chose avec order */}</li>;
})}
</ul>

locals est un objet qui vit et meurt au sein d’une seule route Astro ; lorsque la page de votre route est rendue, locals n’existera plus et un nouvel objet sera créé. Les informations qui doivent persister à travers plusieurs requêtes de pages doivent être stockées ailleurs.

Exemple : Supprimer des informations sensibles

Titre de la section Exemple : Supprimer des informations sensibles

L’exemple ci-dessous utilise un middleware pour remplacer “PRIVATE INFO” par le mot “REDACTED” afin de vous permettre d’afficher le code HTML modifié sur votre page :

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
});
};

Vous pouvez importer et utiliser la fonction utilitaire defineMiddleware() pour bénéficier de la sécurité de type :

src/middleware.ts
import { defineMiddleware } from "astro:middleware";
// `context` et `next` sont automatiquement typés
export const onRequest = defineMiddleware((context, next) => {
});

A la place, si vous utilisez JsDoc pour profiter de la sécurité des types, vous pouvez utiliser MiddlewareHandler :

src/middleware.js
/**
* @type {import("astro").MiddlewareHandler}
*/
// `context` et `next` sont automatiquement typés
export const onRequest = (context, next) => {
};

Pour taper l’information dans Astro.locals, ce qui vous donne l’autocomplétion dans les fichiers .astro et le code middleware, déclarez un espace de noms global dans le fichier env.d.ts :

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

Ensuite, dans le fichier du middleware, vous pouvez tirer parti de l’autocomplétion et de la sécurité des types.

Plusieurs intergiciels peuvent être reliés dans un ordre précis à l’aide de séquence() :

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);

L’ordre de la console sera alors le suivant :

Fenêtre de terminal
validation request
auth request
greeting request
greeting response
auth response
validation response

Ajouté à la version : astro@4.13.0

L’APIContext expose une méthode appelée rewrite() qui fonctionne de la même manière que Astro.rewrite.

Utilisez context.rewrite() dans un middleware pour afficher le contenu d’une autre page sans rediriger votre visiteur vers une nouvelle page. Cela déclenchera une nouvelle phase d’affichage, entraînant la ré-exécution de tout middleware.

src/middleware.js
import { isLoggedIn } from "~/auth.js"
export function onRequest (context, next) {
if (!isLoggedIn(context)) {
// Si l'utilisateur n'est pas connecté, mettre à jour la requête pour afficher la route `/login` et
// ajouter un en-tête pour indiquer où l'utilisateur doit être envoyé après une connexion réussie.
// Ré-exécuter le middleware.
return context.rewrite(new Request("/login", {
headers: {
"x-redirect-to": context.url.pathname
}
}));
}
return next();
};

Vous pouvez également passer à la fonction next() un paramètre optionnel de chemin URL pour réécrire la Request courante sans réenclencher une nouvelle phase de rendu. L’emplacement du chemin de réécriture peut être fourni sous la forme d’une chaîne, d’une URL ou d’une Request :

src/middleware.js
import { isLoggedIn } from "~/auth.js"
export function onRequest (context, next) {
if (!isLoggedIn(context) {
// Si l'utilisateur n'est pas connecté, mettre à jour la requête pour afficher la route `/login` et
// ajouter un en-tête pour indiquer où l'utilisateur doit être envoyé après une connexion réussie.
// Renvoyer un nouveau `contexte` à tous les middlewares suivants.
return next(new Request("/login", {
headers: {
"x-redirect-to": context.url.pathname
}
}));
}
return next();
};

La fonction next() accepte la même charge utile que la fonction Astro.rewrite(). L’emplacement du chemin de réécriture peut être fourni sous la forme d’une chaîne, d’une URL ou d’une Request.

Quand vous avez plusieurs fonctions middleware enchaînées via sequence(), soumettre un chemin à next() réécrira la Request en place et le middleware ne s’exécutera pas à nouveau. Le middleware suivant dans la chaîne recevra la nouvelle Request avec son context mis à jour :

src/middleware.js
// L'URL actuel est https://example.com/blog
// Première fonction du middleware
async function first(_, next) {
console.log(context.url.pathname) // ceci enregistrera "/blog"
// Réécriture vers une nouvelle route, la page d'accueil
// Retourne le `context` mis à jour qui est passé à la fonction suivante
return next("/")
}
// L'URL actuelle est toujours https://example.com/blog
// Deuxième fonction du middleware
async function second(context, next) {
// Reçoit la mise à jour du `context`
console.log(context.url.pathname) // Cela sera affiché dans les logs "/"
return next()
}
export const onRequest = sequence(first, second);

Le middleware tentera de s’exécuter pour toutes les pages rendues à la demande, même lorsqu’un itinéraire correspondant ne peut être trouvé. Cela inclut la page 404 par défaut (vide) d’Astro et toutes les pages 404 personnalisées. Cependant, c’est à l’adaptateur de décider si ce code s’exécute. Certains adaptateurs peuvent servir une page d’erreur spécifique à la plate-forme à la place.

Le middleware tentera également de s’exécuter avant de servir une page d’erreur 500, y compris une page 500 personnalisée, sauf si l’erreur du serveur s’est produite lors de l’exécution du middleware lui-même. Si votre middleware ne s’exécute pas correctement, vous n’aurez pas accès à Astro.locals pour rendre votre page 500.

Contribuer

Comment pouvons-nous vous aider ?

Créer une issue GitHub

Le moyen le plus rapide d'alerter notre équipe d'un problème.

Communauté