Aller au contenu

Routage avancé expérimental

Type : boolean
Par défaut : false

Ajouté à la version : astro@6.3.0 Nouveau

Active src/app.ts comme point d’entrée personnalisé du pipeline de requêtes, vous donnant un contrôle total sur la manière dont Astro gère les requêtes entrantes.

Par défaut, Astro gère chaque requête avec un pipeline intégré qui exécute la normalisation des barres obliques finales, les redirections, les sessions, les actions, les middleware utilisateur, le rendu des pages, l’internationalisation (i18n) et la mise en cache dans un ordre fixe. Le routage avancé vous permet de remplacer ce pipeline par le vôtre, en composant les fonctions de gestion intégrées d’Astro avec une logique personnalisée dans l’ordre de votre choix.

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
advancedRouting: true,
},
});

Lorsque advancedRouting est activé, créez un fichier src/app.ts (ou .js, .mjs, .mts) qui exporte par défaut un objet doté d’une méthode fetch. La méthode fetch reçoit un objet Request standard et doit renvoyer un objet Response.

Si aucun fichier src/app.ts n’existe (ou si advancedRouting n’est pas activée), Astro utilise son pipeline intégré, qui exécute automatiquement toutes les fonctionnalités.

Vous pouvez éventuellement importer le type Fetchable depuis astro pour vérifier le type de votre point d’entrée :

src/app.ts
import type { Fetchable } from 'astro';
export default {
async fetch(request: Request): Promise<Response> {
// ...
},
} satisfies Fetchable;

Par défaut, Astro recherche src/app.ts comme point d’entrée du routage avancé. Transmettez un objet à advancedRouting avec une option fetchFile pour utiliser un fichier différent :

astro.config.mjs
export default defineConfig({
experimental: {
advancedRouting: {
fetchFile: 'fetch.ts',
},
},
});

Avec cette configuration, Astro recherchera src/fetch.ts au lieu de src/app.ts.

Définissez fetchFile sur null pour désactiver complètement le point d’entrée. Cela est utile si vous avez déjà un fichier src/app.ts utilisé à d’autres fins :

astro.config.mjs
export default defineConfig({
experimental: {
advancedRouting: {
fetchFile: null,
},
},
});

La manière la plus simple de commencer est d’utiliser le gestionnaire astro(), qui exécute l’intégralité du pipeline intégré d’Astro (sessions, cache, redirections, barres obliques finales, actions, middleware, pages et i18n) dans l’ordre par défaut. Cela vous permet d’ajouter une logique personnalisée avant ou après Astro sans modifier le fonctionnement du pipeline interne :

src/app.ts
import { FetchState, astro } from 'astro/fetch';
export default {
async fetch(request: Request): Promise<Response> {
const state = new FetchState(request);
// Prétraitement personnalisé, exécuté avant tout gestionnaire Astro
const url = new URL(request.url);
if (url.pathname.startsWith('/tableau-de-bord')) {
const cookie = request.headers.get('cookie') ?? '';
if (!cookie.includes('session=')) {
return new Response(null, {
status: 302,
headers: { Location: '/connexion' },
});
}
}
const response = await astro(state);
// Post-traitement personnalisé, exécuté après le rendu Astro
response.headers.set('X-Powered-By', 'Astro');
return response;
},
};

Pour de nombreux cas d’utilisation, tels que l’ajout de gardes d’authentification, la journalisation des requêtes et les en-têtes personnalisés, astro() est tout ce dont vous avez besoin.

Lorsque vous avez besoin de plus de contrôle sur l’ordre du pipeline, ou si vous souhaitez omettre certaines fonctionnalités, vous pouvez composer des fonctions de gestion individuelles à partir de astro/fetch :

src/app.ts
import {
FetchState,
sessions,
actions,
middleware,
pages,
i18n,
} from 'astro/fetch';
export default {
async fetch(request: Request): Promise<Response> {
const state = new FetchState(request);
await sessions(state);
try {
const actionResponse = await actions(state);
if (actionResponse) return actionResponse;
const response = await middleware(state, (s) => pages(s));
return i18n(state, response);
} finally {
await state.finalizeAll();
}
},
};

Chaque fonction opère sur un objet FetchState qui suit les données par requête comme la route correspondante, les cookies et la session. Vous pouvez les appeler dans n’importe quel ordre et les mélanger avec votre propre logique.

Le principal avantage du routage avancé est la possibilité d’insérer une logique personnalisée n’importe où dans le pipeline de requêtes. Vous pouvez exécuter du code avant qu’Astro ne touche à la requête, entre les étapes du pipeline ou après la production de la réponse.

Le gestionnaire astro() est le moyen le plus simple d’ajouter un prétraitement ou un post-traitement autour de l’ensemble du pipeline. Lorsque vous devez insérer une logique entre des étapes spécifiques, comme exécuter du code personnalisé après les actions mais avant le rendu de la page, composez plutôt les gestionnaires individuels :

src/app.ts
import {
FetchState,
actions,
middleware,
pages,
i18n,
} from 'astro/fetch';
export default {
async fetch(request: Request): Promise<Response> {
const state = new FetchState(request);
const actionResponse = await actions(state);
if (actionResponse) return actionResponse;
// Logique personnalisée entre les actions et le rendu de la page
console.log(`Rendu de ${new URL(request.url).pathname}`);
const response = await middleware(state, (s) => pages(s));
return i18n(state, response);
},
};

Définition du type des fournisseurs personnalisés avec App.Providers

Section intitulée « Définition du type des fournisseurs personnalisés avec App.Providers »

Lorsque vous enregistrez des fournisseurs de contexte personnalisés avec state.provide(), vous pouvez déclarer leurs types en utilisant l’interface App.Providers afin que Astro et ctx soient entièrement typés dans vos composants et middleware :

src/env.d.ts
declare namespace App {
interface Providers {
oauth: import('./lib/oauth').OAuthSession;
}
}

Après avoir déclaré un fournisseur, ctx.oauth (et Astro.oauth dans les fichiers .astro) sera typé automatiquement.

Toutes les fonctions de gestion sont importées depuis astro/fetch et opèrent sur un objet FetchState.

L’objet d’état par requête. Créez-en un au début de votre méthode fetch :

import { FetchState } from 'astro/fetch';
const state = new FetchState(request);

FetchState suit la route correspondante, les cookies, les fournisseurs de session et d’autres données par requête. Toutes les fonctions de gestion nécessitent cet objet comme premier argument.

Type : Request

L’objet Request entrant.

Type : URL

Une URL normalisée dérivée de la requête.

Type : string

Le chemin de la requête, décodé et sans le préfixe de base (par exemple /a-propos ou /blog/mon-article).

Type : RouteData | undefined

La route correspondante pour cette requête, le cas échéant. Elle est résolue automatiquement lors de la création de FetchState.

Type : AstroCookies

Une instance AstroCookies pour lire et définir des cookies sur cette requête.

Type : App.Locals

Un objet limité à la requête pour stocker des données personnalisées. Il s’agit du même objet locals disponible dans les middlewares et les routes d’API.

Type : Params | undefined

Les paramètres de la route dérivés de la route correspondante et du chemin (par exemple { slug: 'mon-article' } pour une route [slug].astro).

Type : number
Par défaut : 200

Le code de statut HTTP pour la réponse. Vous pouvez le définir avant le rendu pour contrôler le statut de la réponse (par exemple state.status = 404).

Type : Response | undefined
Par défaut : undefined

La réponse (Response) produite par les gestionnaires après le rendu. Elle est définie automatiquement par pages() et middleware(), ce qui vous permet d’inspecter ou d’utiliser la réponse plus tard dans le pipeline :

const response = await middleware(state, (s) => pages(s));
// state.response est maintenant le même objet que response

Type : (payload: RewritePayload) => Promise<Response>

Déclenche une réécriture vers une autre route. Le payload peut être un chemin sous forme de chaîne de caractères ('/autre-page'), une URL ou un objet Request :

const response = await state.rewrite('/autre-page');

Type : (key: string, provider: ContextProvider<T>) => void

Enregistre un fournisseur de contexte sous le nom de propriété donné. La fonction create() du fournisseur est appelée de manière paresseuse lors du premier state.resolve(), et son rappel optionnel finalize() s’exécute lors de state.finalizeAll() :

state.provide('monService', {
create: () => new MonService(),
finalize: (service) => service.close(),
});

Type : (key: string) => T | undefined

Renvoie la valeur d’un fournisseur précédemment enregistré, en appelant sa fonction create lors du premier accès. Renvoie undefined si aucun fournisseur n’a été enregistré pour le nom de propriété :

const service = state.resolve('monService');

Type : () => Promise<void> | void

Exécute tous les rappels finalize des fournisseurs enregistrés. Appelez ceci après que la réponse a été produite, généralement dans un bloc finally, pour persister les données de session et nettoyer les ressources :

await sessions(state);
try {
// ...pipeline de rendu...
return response;
} finally {
await state.finalizeAll();
}

Type : (state: FetchState) => Promise<Response>

Le gestionnaire tout-en-un qui exécute l’ensemble du pipeline d’Astro (sessions, cache, redirections, barre oblique finale, actions, middleware, pages et i18n) dans l’ordre par défaut. Utilisez ceci lorsque vous souhaitez ajouter une logique avant ou après Astro sans modifier l’ordre interne du pipeline :

src/app.ts
import { FetchState, astro } from 'astro/fetch';
export default {
async fetch(request: Request): Promise<Response> {
const state = new FetchState(request);
// Prétraitement personnalisé ici...
const response = await astro(state);
// Post-traitement personnalisé ici...
return response;
},
};

Type : (state: FetchState) => Promise<Response>

Transmet la requête à la route Astro correspondante (page, point de terminaison ou solution de repli). Il s’agit du gestionnaire de rendu principal, et la plupart des pipelines personnalisés l’incluent.

Type : (state: FetchState, next: (state: FetchState) => Promise<Response>) => Promise<Response>

Exécute la chaîne de middleware d’Astro (depuis src/middleware.ts). Le rappel next est appelé au bas de la chaîne pour produire la réponse, généralement en appelant pages() :

const response = await middleware(state, (s) => pages(s));

Type : (state: FetchState) => Promise<Response | undefined> | undefined

Gère les actions d’Astro (RPC et soumissions de formulaires). Renvoie une Response pour les actions RPC, ou undefined pour les actions de formulaire et les requêtes ne constituant pas une action. Vérifiez la valeur de retour pour décider s’il faut poursuivre le rendu :

const actionResponse = await actions(state);
if (actionResponse) return actionResponse;
// sinon, continuez le rendu de la page...

Type : (state: FetchState) => Promise<void> | void

Enregistre le fournisseur de sessions. Les sessions sont créées de manière paresseuse lorsque votre code accède à ctx.session et sont persistées lorsque state.finalizeAll() est appelé. Appelez ceci tôt dans le pipeline, et appelez finalizeAll() dans un bloc finally :

await sessions(state);
try {
// ...pipeline de rendu...
} finally {
await state.finalizeAll();
}

Type : (state: FetchState, response: Response) => Promise<Response>

Post-traite une réponse en fonction de votre configuration i18n. Gère les redirections de paramètres régionaux, les erreurs 404 pour les paramètres régionaux invalides et le routage de repli. Appelez cette fonction après le rendu :

const response = await middleware(state, (s) => pages(s));
return i18n(state, response);

Type : (state: FetchState) => Promise<Response> | undefined

Gère les routes de redirection définies dans votre configuration d’Astro. Renvoie une réponse de redirection (Response) si la route correspondante est une redirection, ou undefined si l’appelant doit continuer le traitement.

Type : (state: FetchState, next: () => Promise<Response>) => Promise<Response>

Enveloppe un rappel de rendu avec la logique du fournisseur de cache (EN). Gère la mise en cache à l’exécution, les fournisseurs basés sur le CDN et le cas sans cache.

Type : (state: FetchState) => Response | undefined

Vérifie si le chemin d’accès à la requête nécessite une normalisation des barres obliques finales et renvoie une réponse de redirection (Response) le cas échéant. Renvoie undefined si aucune redirection n’est nécessaire.

Astro fournit également des enveloppes compatibles avec Hono pour toutes les fonctions de gestion via astro/hono. Si vous préférez utiliser Hono comme framework de routage, vous pouvez exporter une application Hono depuis src/app.ts :

src/app.ts
import { Hono } from 'hono';
import { logger } from 'hono/logger';
import { actions, middleware, pages, i18n } from 'astro/hono';
const app = new Hono();
// Middleware Hono
app.use(logger());
// Gestionnaires d'Astro (en tant que middleware Hono)
app.use(actions());
app.use(middleware());
app.use(pages());
app.use(i18n());
export default app;

Le module astro/hono exporte les mêmes noms de gestionnaires que astro/fetch (astro, pages, middleware, actions, sessions, redirects, cache, i18n, trailingSlash), mais chacun renvoie une fonction middleware Hono. Cela vous permet de mélanger les gestionnaires d’Astro avec n’importe quel middleware Hono de l’écosystème.

Contribuer Communauté Parrainer