Gestionnaire
Aperçu rapide
Le gestionnaire est un concept central dans le framework Salvo, qui peut être simplement compris comme une unité de traitement des requêtes. Il a deux objectifs principaux :
-
En tant que point de terminaison : Un objet implémentant
Handlerpeut être placé dans le système de routage comme point de terminaison final pour traiter les requêtes. Lors de l'utilisation de la macro#[handler], une fonction peut être directement utilisée comme point de terminaison ; tandis que l'utilisation de la macro#[endpoint]permet non seulement de servir de point de terminaison, mais génère également automatiquement la documentation OpenAPI (cela sera détaillé dans la documentation ultérieure). -
En tant que middleware : Le même
Handlerpeut également être utilisé comme middleware pour traiter les requêtes avant ou après qu'elles atteignent le point de terminaison final.
Le flux de traitement des requêtes de Salvo peut être vu comme un "pipeline" : une requête passe d'abord par une série de middlewares (traitement vertical) puis atteint le point de terminaison correspondant (traitement horizontal). Les middlewares et les points de terminaison sont tous deux des implémentations de Handler, ce qui garantit la cohérence et la flexibilité de l'ensemble du système.
Diagramme de flux du gestionnaire dans Salvo
Middleware et modèle en oignon
L'essence du modèle en oignon est qu'en plaçant ctrl.call_next() avant et après une logique spécifique, il met en œuvre un flux de traitement bidirectionnel pour les requêtes et les réponses, permettant à chaque middleware de participer au cycle complet requête-réponse.
Structure d'exemple complète de middleware
Qu'est-ce qu'un gestionnaire
Un gestionnaire est l'objet concret responsable du traitement des objets Request. Handler est lui-même un trait contenant une méthode asynchrone handle :
La signature par défaut de la fonction handle comprend quatre paramètres, dans l'ordre : &mut Request, &mut Depot, &mut Response, &mut FlowCtrl. Depot est un stockage temporaire qui peut contenir des données liées à la requête en cours.
Selon son utilisation, il peut servir de middleware (hoop), qui peut effectuer un traitement avant ou après que la requête atteigne le Handler de traitement formel des requêtes, comme : vérification de connexion, compression de données, etc.
Le middleware est ajouté via la fonction hoop d'un Router. Le middleware ajouté affecte le Router actuel et tous ses Router descendants.
Un Handler peut également être utilisé comme un Handler qui participe à la correspondance de route et est finalement exécuté, appelé goal.
Handler en tant que middleware (hoop)
Lorsqu'un Handler agit en tant que middleware, il peut être ajouté aux trois types d'objets suivants qui prennent en charge le middleware :
Service: Toute requête passera par le middleware dans leService.Router: Ce n'est que lorsque la correspondance de route réussit que la requête passera par le middleware défini dans leServiceet tout le middleware collecté le long du chemin de correspondance.Catcher: Lorsqu'une erreur se produit et qu'aucune information d'erreur personnalisée n'a été écrite, la requête passera par le middleware dans leCatcher.Handler: LeHandlerlui-même prend en charge l'ajout d'encapsulations de middleware pour exécuter une logique pré- ou post-traitement.
Utilisation de la macro #[handler]
La macro #[handler] peut grandement simplifier l'écriture du code et améliorer la flexibilité du code.
Elle peut être appliquée à une fonction pour la faire implémenter Handler :
Cela équivaut à :
Comme vous pouvez le voir, avec #[handler], le code devient beaucoup plus simple :
- Pas besoin d'ajouter manuellement
#[async_trait]. - Les paramètres inutiles dans la fonction sont omis, et les paramètres requis peuvent être arrangés dans n'importe quel ordre.
- Pour les objets implémentant les abstractions
WriterouScribe, ils peuvent être directement retournés comme valeur de retour de la fonction. Ici,&'static strimplémenteScribe, donc il peut être directement retourné.
#[handler] peut non seulement être appliqué à des fonctions, mais aussi au bloc impl d'une struct pour faire implémenter Handler par la struct. Dans ce cas, la fonction handle à l'intérieur du bloc impl est reconnue comme l'implémentation concrète de la méthode handle dans Handler :
Gestion des erreurs
Dans Salvo, un Handler peut retourner un Result, à condition que les types Ok et Err à l'intérieur du Result implémentent le trait Writer.
Considérant l'utilisation répandue d'anyhow, lorsque la fonctionnalité anyhow est activée, anyhow::Error implémentera le trait Writer. anyhow::Error sera mappé sur InternalServerError.
Pour les types d'erreur personnalisés, vous pouvez afficher différentes pages d'erreur selon les besoins.