Routeur personnalisé
La fonctionnalité de routeur personnalisé insère la logique de routage définie par le plug-in avant le routeur intégré de bext. Il existe pour les cas que le routeur-cadre ne gère délibérément pas : schémas d'URL hérités importés d'autres CMS, correspondance basée sur les étiquettes de style Traefik, tables de redirection en masse, mode maintenance.
Quand l'utiliser#
- Vous migrez hors WordPress / Drupal / Ghost et devez honorer
permaliens existants (
/?p=123,/node/42,/2024/03/hello-world/). - Vous avez besoin d'un système d'étiquettes de style Traefik où les déploiements annotent les itinéraires au moment du push plutôt qu'au moment de la configuration.
- Vous souhaitez une liste 410 Gone pour les URL qui n'existent plus.
- Vous voulez un routeur en mode maintenance qui court-circuite tous les demande à une page d’attente pendant l’exécution d’une migration.
Si votre routage réside dans un fichier de configuration statique et utilise des
Style /posts/:slug, le routeur intégré le gère déjà. Recherchez un routeur personnalisé lorsque les règles sont dynamiques, héritées ou basées sur des étiquettes.
Le trait#
pub trait CustomRouterPlugin: Send + Sync {
fn name(&self) -> &str;
fn order(&self) -> i32 { 0 } // lower runs first; negative allowed
fn route(&self, req: &RouterRequest) -> Result<RouteDecision, RouterError>;
}
Plusieurs routeurs peuvent être installés simultanément. Ils fonctionnent dans l'ordre croissant order() ; le premier routeur à renvoyer autre chose que Pass gagne. Un routeur avec order() = -1000 précède tous les autres routeurs, ce qui est utile pour le mode maintenance.
Types de clés#
| Taper | But |
|---|---|
RouterRequest |
Instantané de requête ABI-flat : method, host, path, query, headers. |
RouteDecision::Match |
{ handler_id, params } — la demande est résolue. |
RouteDecision::Pass |
Ce routeur refuse ; le suivant court. |
RouteDecision::Rewrite |
{ new_path } : modifiez le chemin et redémarrez le pipeline. |
RouteDecision::Respond |
{ status, headers, body } — court-circuit avec réponse complète. |
RouterError |
Malformed (400), Backend (500). |
RouterRequest::header(name) effectue une recherche insensible à la casse et renvoie la première correspondance.
Variantes de décision en pratique#
| Variante | Exemple de cas d'utilisation |
|---|---|
Match |
Lien permanent WordPress résolu vers le gestionnaire posts.show. |
Pass |
Le routeur ne reconnaît pas l'URL ; laissez le prochain essayer. |
Rewrite |
Héritage /old/blog/:slug → /posts/:slug. |
Respond |
Redirection 301, 410 Gone, page d'attente en mode maintenance. |
Rewrite redémarre l'intégralité du pipeline du routeur avec le nouveau chemin. Le moteur d'exécution applique une protection contre les boucles afin qu'un routeur qui réécrit toujours sur le même chemin ne puisse pas bloquer la requête.
RouteDecision::Rewrite redémarre l'intégralité du pipeline du routeur à partir du premier plugin. Une chaîne de deux routeurs qui réécrivent chacun le même chemin bouclera jusqu'à ce que le dispositif de protection contre les boucles du runtime tue la requête. Assurez-vous toujours que le chemin réécrit ne correspond plus à la même règle.
Implémentation de référence : @bext/router-legacy#
@bext/router-legacy fait correspondre les modèles d'URL avec les caractères génériques :param et réécrit ou redirige. Les règles sont présentes dans la configuration :
[[plugins]]
name = "router-legacy"
source = "@bext/router-legacy"
order = -100 # run before the built-in router
# WordPress-style permalinks → new post handler
[[plugins.rules]]
match = "/old/blog/:slug"
action = "rewrite"
target = "/posts/:slug"
# Year-based archive → section
[[plugins.rules]]
match = "/archive/:year/:month"
action = "rewrite"
target = "/posts?year=:year&month=:month"
# Deleted content → 410 Gone
[[plugins.rules]]
match = "/retired/*"
action = "respond"
status = 410
body = "This page has been retired."
Le même effet dans Rust :
use bext_plugin_api::router::*;
use std::collections::HashMap;
struct LegacyRouter;
impl CustomRouterPlugin for LegacyRouter {
fn name(&self) -> &str { "legacy" }
fn order(&self) -> i32 { -100 }
fn route(&self, req: &RouterRequest) -> Result<RouteDecision, RouterError> {
if let Some(slug) = req.path.strip_prefix("/old/blog/") {
return Ok(RouteDecision::Rewrite {
new_path: format!("/posts/{slug}"),
});
}
if req.path.starts_with("/retired/") {
return Ok(RouteDecision::Respond {
status: 410,
headers: vec![("Content-Type".into(), "text/plain".into())],
body: b"This page has been retired.".to_vec(),
});
}
Ok(RouteDecision::Pass)
}
}
Indicateur de fonctionnalité#
Aucun. Le trait et les types de routeur résident dans bext-plugin-api et sont toujours disponibles ; aucune fonction de chargement ne les bloque.
Voir aussi#
@bext/router-legacy— gestionnaire d'URL hérité basé sur des modèles.- Guide d'itinéraire — les règles de correspondance du routeur intégré qui s'exécutent après que tous les routeurs personnalisés renvoient
Pass. - Guide de migration nginx — migration des règles de réécriture nginx héritées vers des routeurs personnalisés bext.
- Routage des frameworks — routage du système de fichiers pour PRISM et d'autres intégrations de framework.
- Aperçu des capacités — la liste complète des fonctionnalités enfichables.