Depot

Depot wird verwendet, um temporäre Daten zu speichern, die während einer einzelnen Anfrage verarbeitet werden. Middleware kann die von ihr verarbeiteten temporären Daten im Depot ablegen, damit nachfolgende Programme darauf zugreifen können.

Wenn ein Server eine Anfrage von einem Client-Browser empfängt, erstellt er eine Instanz von Depot. Diese Instanz wird zerstört, nachdem alle Middleware-Komponenten und der Handler die Anfrage verarbeitet haben.

Beispielsweise können wir in einer Login-Middleware current_user setzen und dann in nachfolgender Middleware oder im Handler die Informationen des aktuellen Benutzers auslesen.

Schnellverständnis

Depot dient der Speicherung und dem Austausch von Daten während der Anfrageverarbeitung. Es implementiert einen typsicheren Datencontainer, der zwei Hauptnutzungsmuster unterstützt:

  1. Schlüssel-Wert-Speicher: Zugriff auf Werte über Zeichenfolgenschlüssel mittels insert/get-Methoden.
  2. Typinjektion: Speichern und Abrufen von Werten basierend auf ihrem Typ mittels inject/obtain-Methoden.

Wie die Beispiele zeigen, ist Depot besonders nützlich für die Datenweitergabe zwischen Middleware und Handlern. Middleware kann Werte im Depot setzen (wie Benutzerinformationen, Authentifizierungsstatus), und nachfolgende Handler können diese Werte abrufen, ohne redundante Berechnungen oder Abfragen durchführen zu müssen. Das Design von Depot gewährleistet Datenkonsistenz und -zugänglichkeit über die gesamte Anfrageverarbeitungskette hinweg und macht es zu einem Kernwerkzeug für den Aufbau komplexer Webanwendungen.

main.rs
Cargo.toml
use salvo::prelude::*;

#[handler]
async fn set_user(depot: &mut Depot) {
    depot.insert("user", "client");
}
#[handler]
async fn hello(depot: &mut Depot) -> String {
    format!(
        "Hello {}",
        depot.get::<&str>("user").copied().unwrap_or_default()
    )
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt().init();

    let router = Router::new().hoop(set_user).goal(hello);

    let acceptor = TcpListener::new("0.0.0.0:8698").bind().await;
    Server::new(acceptor).serve(router).await;
}

Setzen und Abrufen von Daten über insert und get

Wie oben gezeigt, können Sie mit insert einen Schlüssel und einen Wert in das Depot einfügen. Für Werte dieses Typs können Sie sie direkt mit get abrufen.

depot.insert("a", "b");
assert_eq!(depot.get::<&str>("a").copied().unwrap(), "b")

Wenn der Schlüssel nicht existiert oder der Schlüssel existiert, aber der Typ nicht übereinstimmt, wird None zurückgegeben.

Setzen und Abrufen von Daten über inject und obtain

Manchmal gibt es Szenarien, in denen für einen Typ eine eindeutige Instanz existiert, ohne dass diese einem spezifischen Schlüssel zugeordnet werden muss. Sie können inject verwenden, um Daten einzufügen, und dann obtain, um sie abzurufen. Diese Methoden erfordern keine Angabe eines Schlüssels.

depot.inject(Config::new());
depot.obtain::<Config>();

Übersicht der Depot-Struct-Methoden

KategorieMethodeBeschreibung
Erstellung/Kapazitätnew()Erstellt ein leeres Depot
with_capacity(capacity)Erstellt ein Depot mit angegebener Kapazität
capacity()Ruft die Kapazität ab
inner()Ruft eine Referenz auf die interne HashMap ab
Typinjektion/-abrufinject<V>(value)Injiziert einen Wert nach Typ
obtain<T>()Ruft eine Referenz auf den injizierten Wert ab
obtain_mut<T>()Ruft eine mutable Referenz auf den injizierten Wert ab
contains<T>()Prüft, ob ein bestimmter Typ enthalten ist
scrape<T>()Entfernt und gibt den injizierten Wert zurück
Schlüssel-Wert-Operationeninsert(key, value)Fügt ein Schlüssel-Wert-Paar ein
get<V>(key)Ruft eine Referenz auf den zum Schlüssel gehörenden Wert ab
get_mut<V>(key)Ruft eine mutable Referenz auf den zum Schlüssel gehörenden Wert ab
contains_key(key)Prüft, ob ein bestimmter Schlüssel enthalten ist
remove<V>(key)Entfernt den Schlüssel und gibt den Wert zurück
delete(key)Löscht das Schlüssel-Wert-Paar