Session

提供對 Session 支援的中介軟體。

什麼是Session

Session是在伺服器端儲存的一段使用者資料,通常用於追蹤使用者狀態和保存臨時資料。在Web應用中,Session能夠解決HTTP協議無狀態的問題,讓伺服器能夠識別來自同一使用者的多次請求。

Salvo中的Session使用

在Salvo中,Session中介軟體提供了簡單的API來讀取和寫入會話資料。透過SessionDepot可以獲取會話實例,透過getsetremove等方法可以管理會話資料。

常見用途

  • 使用者身份驗證與登入狀態管理
  • 表單資料暫存
  • 使用者偏好設定儲存

範例程式碼

main.rs
Cargo.toml
session-login/src/main.rs
use salvo::prelude::*;
use salvo::session::{CookieStore, Session, SessionDepotExt, SessionHandler};

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt().init();
    let session_handler = SessionHandler::builder(
        CookieStore::new(),
        b"secretabsecretabsecretabsecretabsecretabsecretabsecretabsecretab",
    )
    .build()
    .unwrap();
    let router = Router::new()
        .hoop(session_handler)
        .get(home)
        .push(Router::with_path("login").get(login).post(login))
        .push(Router::with_path("logout").get(logout));

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

#[handler]
pub async fn login(req: &mut Request, depot: &mut Depot, res: &mut Response) {
    if req.method() == salvo::http::Method::POST {
        let mut session = Session::new();
        session
            .insert("username", req.form::<String>("username").await.unwrap())
            .unwrap();
        depot.set_session(session);
        res.render(Redirect::other("/"));
    } else {
        res.render(Text::Html(LOGIN_HTML));
    }
}

#[handler]
pub async fn logout(depot: &mut Depot, res: &mut Response) {
    if let Some(session) = depot.session_mut() {
        session.remove("username");
    }
    res.render(Redirect::other("/"));
}

#[handler]
pub async fn home(depot: &mut Depot, res: &mut Response) {
    let mut content = r#"<a href="login">Login</h1>"#.into();
    if let Some(session) = depot.session_mut() {
        if let Some(username) = session.get::<String>("username") {
            content = format!(r#"Hello, {username}. <br><a href="logout">Logout</h1>"#);
        }
    }
    res.render(Text::Html(content));
}

static LOGIN_HTML: &str = r#"<!DOCTYPE html>
<html>
    <head>
        <title>Login</title>
    </head>
    <body>
        <form action="/login" method="post">
            <h1>Login</h1>
            <input type="text" name="username" />
            <button type="submit" id="submit">Submit</button>
        </form>
    </body>
</html>
"#;