Rust Web框架中如何跨路由函数读取变量
Rust Web项目中跨路由传递变量的解决方案
因为POST和GET是两个独立的请求,内存里的局部变量无法直接共享,下面提供三种实用的实现方案:
方案1:通过URL查询参数传递(简单直接,适合临时传递)
直接在重定向时把参数拼到URL上,GET路由读取即可,无需额外依赖。
修改POST路由:
#[post("/select_date", data = "<time>")] fn select_date(time: Form<SelectDate>) -> Result<Redirect, Error> { println!("{:#?}", time.date); // 对日期做URL编码,避免特殊字符破坏URL结构 Ok(Redirect::to(&format!("/?f_time={}", urlencoding::encode(&time.date)))) }
需要在Cargo.toml添加URL编码依赖:
urlencoding = "2.1"
修改GET路由接收参数:
use actix_web::web::Query; use std::collections::HashMap; #[get("/")] async fn index(user: Option<User>, query: Option<Query<HashMap<String, String>>>) -> Template { // 从查询参数中提取f_time,无值时用空字符串 let f_time = query .and_then(|q| q.get("f_time").cloned()) .unwrap_or_default(); Template::render("index", json!({ "user": user, "f_time": f_time })) }
方案2:使用Session存储(适合用户关联的临时数据)
如果不想把参数暴露在URL里,或者需要和用户绑定,可以用Session存储。以Actix-web为例:
- 添加依赖到
Cargo.toml:
actix-session = "0.7" serde = { version = "1.0", features = ["derive"] }
- 在应用初始化时配置Session中间件:
use actix_session::{Session, CookieSessionStore, SessionMiddleware}; use rand::Rng; #[actix_web::main] async fn main() -> std::io::Result<()> { // 生产环境请将密钥存在配置文件,不要硬编码 let secret_key = rand::thread_rng().gen::<[u8; 32]>(); HttpServer::new(move || { App::new() .wrap(SessionMiddleware::new( CookieSessionStore::default(), &secret_key, )) .service(select_date) .service(index) }) .bind(("127.0.0.1", 8080))? .run() .await }
- 修改POST路由存入Session:
use actix_session::Session; #[post("/select_date", data = "<time>")] fn select_date(time: Form<SelectDate>, session: Session) -> Result<Redirect, Error> { println!("{:#?}", time.date); // 将日期存入Session session.insert("f_time", &time.date)?; Ok(Redirect::to("/")) }
- 修改GET路由从Session读取:
#[get("/")] async fn index(user: Option<User>, session: Session) -> Template { // 从Session读取值,无值时用空字符串 let f_time = session.get::<String>("f_time").unwrap_or_default(); // 若无需保留数据,可读取后删除:session.remove("f_time"); Template::render("index", json!({ "user": user, "f_time": f_time })) }
方案3:使用数据库/缓存(适合长期或全局共享数据)
如果需要长期存储数据,或者让多个请求/用户共享,可以用数据库或缓存。以SQLite为例:
- 添加依赖:
sqlx = { version = "0.7", features = ["sqlite", "runtime-actix-native-tls"] }
- 初始化数据库连接:
use sqlx::SqlitePool; #[actix_web::main] async fn main() -> std::io::Result<()> { let pool = SqlitePool::connect("sqlite:data.db").await.unwrap(); // 初始化数据表(首次运行时执行) sqlx::query("CREATE TABLE IF NOT EXISTS user_data (user_id INTEGER, f_time TEXT)") .execute(&pool) .await .unwrap(); HttpServer::new(move || { App::new() .data(pool.clone()) .service(select_date) .service(index) }) .bind(("127.0.0.1", 8080))? .run() .await }
- 修改POST路由存入数据库(假设用户有唯一ID):
#[post("/select_date", data = "<time>")] async fn select_date( time: Form<SelectDate>, user: Option<User>, pool: web::Data<SqlitePool>, ) -> Result<Redirect, Error> { if let Some(user) = user { // 插入或更新用户的日期数据 sqlx::query("INSERT OR REPLACE INTO user_data (user_id, f_time) VALUES (?, ?)") .bind(user.id) .bind(&time.date) .execute(pool.get_ref()) .await?; } Ok(Redirect::to("/")) }
- 修改GET路由从数据库读取:
#[get("/")] async fn index( user: Option<User>, pool: web::Data<SqlitePool>, ) -> Template { let f_time = if let Some(user) = user { sqlx::query_scalar("SELECT f_time FROM user_data WHERE user_id = ?") .bind(user.id) .fetch_optional(pool.get_ref()) .await .unwrap_or_default() .unwrap_or_default() } else { String::new() }; Template::render("index", json!({ "user": user, "f_time": f_time })) }
内容的提问来源于stack exchange,提问作者GranBoh
相关产品推荐
相关产品推荐

