Handler ist ein zentrales Konzept im Salvo-Framework und kann vereinfacht als Anfrageverarbeitungseinheit verstanden werden. Es hat zwei Hauptanwendungsfälle:
Als Endpunkt (Endpoint): Objekte, die Handler
implementieren, können als Endpunkte im Routingsystem platziert werden, um Anfragen final zu bearbeiten. Durch das #[handler]
-Makro können Funktionen direkt als Endpunkte verwendet werden; mit dem #[endpoint]
-Makro können sie nicht nur als Endpunkt dienen, sondern auch automatisch OpenAPI-Dokumentation generieren (dies wird in späteren Dokumenten näher erläutert).
Als Middleware: Derselbe Handler
kann auch als Middleware eingesetzt werden, um Anfragen vor oder nach Erreichen des finalen Endpunkts zu verarbeiten.
Der Anfrageverarbeitungsfluss in Salvo kann als "Pipeline" betrachtet werden: Eine Anfrage durchläuft zunächst eine Reihe von Middlewares (vertikale Verarbeitung), bevor sie den passenden Endpunkt erreicht (horizontale Verarbeitung). Sowohl Middlewares als auch Endpunkte sind Implementierungen von Handler
, was dem System Konsistenz und Flexibilität verleiht.
Das Wesen des Zwiebelmodells liegt darin, durch die Positionierung von ctrl.call_next()
vor und nach der Verarbeitung einen bidirektionalen Anfrage-Antwort-Zyklus zu ermöglichen, sodass jede Middleware am vollständigen Anfrage-Antwort-Prozess teilnehmen kann.
Ein Handler ist ein Objekt, das für die Verarbeitung von Request-Anfragen verantwortlich ist. Handler ist selbst ein Trait, der eine asynchrone handle
-Methode enthält:
Die Standard-Signatur der handle
-Funktion umfasst vier Parameter: &mut Request, &mut Depot. &mut Response, &mut FlowCtrl
. Depot ist ein temporärer Speicher, der datenbezogene Informationen für die aktuelle Anfrage speichern kann.
Abhängig vom Verwendungszweck kann es als Middleware (Hoop) eingesetzt werden, die vor oder nach der eigentlichen Anfrageverarbeitung durch den Handler
bestimmte Aufgaben erledigt, wie z.B. Login-Validierung oder Datenkomprimierung.
Middleware wird über die hoop
-Funktion des Router
hinzugefügt. Die hinzugefügte Middleware beeinflusst den aktuellen Router
und alle seine untergeordneten Router
.
Ein Handler
kann auch als Handler
verwendet werden, der am Routing teilnimmt und schließlich ausgeführt wird, was als goal
bezeichnet wird.
Handler
als Middleware (Hoop)Wenn Handler
als Middleware verwendet wird, kann es zu den folgenden drei Objekten hinzugefügt werden, die Middleware unterstützen:
Service
: Jede Anfrage durchläuft die Middleware im Service
.
Router
: Nur wenn das Routing erfolgreich ist, durchläuft die Anfrage nacheinander alle definierten Middlewares im Service
und alle gesammelten Middlewares entlang des übereinstimmenden Pfads.
Catcher
: Wenn ein Fehler auftritt und keine benutzerdefinierten Fehlerinformationen geschrieben wurden, durchläuft die Anfrage die Middleware im Catcher
.
Handler
: Handler
selbst unterstützt das Hinzufügen von Middleware-Wrappern, um Vor- oder Nachbearbeitungslogik auszuführen.
#[handler]
-MakrosDas #[handler]
-Makro kann den Code erheblich vereinfachen und die Flexibilität erhöhen.
Es kann auf eine Funktion angewendet werden, um sie als Handler
zu implementieren:
Dies entspricht:
Wie zu sehen ist, wird der Code mit #[handler]
viel einfacher:
#[async_trait]
ist nicht mehr erforderlich.Writer
- oder Scribe
-Abstraktion implementieren, können sie direkt als Rückgabewert der Funktion verwendet werden. Hier implementiert &'static str
Scribe
und kann daher direkt als Funktionsrückgabewert zurückgegeben werden.Das #[handler]
-Makro kann nicht nur auf Funktionen, sondern auch auf impl
-Blöcke für struct
angewendet werden, um den struct
als Handler
zu implementieren. In diesem Fall wird die handle
-Funktion im impl
-Block als spezifische Implementierung der handle
-Methode in Handler
erkannt:
Handler in Salvo können Result
zurückgeben, solange die Typen Ok
und Err
in Result
das Writer
-Trait implementieren.
In Anbetracht der weit verbreiteten Verwendung von anyhow implementiert anyhow::Error
das Writer
-Trait, wenn das anyhow
-Feature aktiviert ist. anyhow::Error
wird auf InternalServerError
abgebildet.
Für benutzerdefinierte Fehlertypen können Sie je nach Bedarf unterschiedliche Fehlerseiten ausgeben.