状态管理 #

Rocket提供了多种状态管理方式,可以在应用级别和请求级别共享数据。本节将介绍如何有效地管理应用状态。

应用状态 #

使用manage添加状态 #

rust
use std::sync::Mutex;
use std::collections::HashMap;

struct AppState {
    counter: Mutex<u32>,
    users: Mutex<HashMap<u32, String>>,
}

#[launch]
fn rocket() -> _ {
    let state = AppState {
        counter: Mutex::new(0),
        users: Mutex::new(HashMap::new()),
    };
    
    rocket::build()
        .manage(state)
        .mount("/", routes![increment, get_count])
}

使用State获取状态 #

rust
use rocket::State;

#[get("/count")]
fn get_count(state: &State<AppState>) -> String {
    let count = state.counter.lock().unwrap();
    format!("Count: {}", *count)
}

#[get("/increment")]
fn increment(state: &State<AppState>) -> String {
    let mut count = state.counter.lock().unwrap();
    *count += 1;
    format!("Count: {}", *count)
}

多状态管理 #

添加多个状态 #

rust
#[launch]
fn rocket() -> _ {
    rocket::build()
        .manage(DbPool::new())
        .manage(Config::from_env())
        .manage(Cache::new())
        .mount("/", routes![get_user])
}

获取多个状态 #

rust
#[get("/user/<id>")]
fn get_user(
    db: &State<DbPool>,
    cache: &State<Cache>,
    config: &State<Config>,
) -> String {
    format!("Getting user with config: {:?}", config)
}

数据库连接池 #

简单连接池 #

rust
use std::sync::Arc;
use tokio::sync::Mutex;

pub struct DbPool {
    connections: Arc<Mutex<Vec<DbConnection>>>,
}

impl DbPool {
    pub fn new() -> Self {
        Self {
            connections: Arc::new(Mutex::new(Vec::new())),
        }
    }
    
    pub async fn get_connection(&self) -> DbConnection {
        DbConnection
    }
}

pub struct DbConnection;

impl DbConnection {
    pub async fn query(&self, sql: &str) -> Vec<String> {
        vec!["result".to_string()]
    }
}

使用连接池 #

rust
#[get("/users")]
async fn list_users(pool: &State<DbPool>) -> String {
    let conn = pool.get_connection().await;
    let users = conn.query("SELECT * FROM users").await;
    format!("Users: {:?}", users)
}

配置管理 #

配置结构 #

rust
use std::env;

#[derive(Debug, Clone)]
pub struct Config {
    pub database_url: String,
    pub jwt_secret: String,
    pub server_port: u16,
    pub debug: bool,
}

impl Config {
    pub fn from_env() -> Self {
        Self {
            database_url: env::var("DATABASE_URL")
                .unwrap_or_else(|_| "postgres://localhost/mydb".to_string()),
            jwt_secret: env::var("JWT_SECRET")
                .unwrap_or_else(|_| "secret".to_string()),
            server_port: env::var("PORT")
                .map(|p| p.parse().unwrap_or(8000))
                .unwrap_or(8000),
            debug: env::var("DEBUG")
                .map(|d| d == "true")
                .unwrap_or(false),
        }
    }
}

使用配置 #

rust
#[get("/config")]
fn show_config(config: &State<Config>) -> String {
    format!("Running on port {}, debug: {}", config.server_port, config.debug)
}

缓存管理 #

内存缓存 #

rust
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use std::time::{Duration, Instant};

pub struct Cache {
    data: Arc<RwLock<HashMap<String, CacheEntry>>>,
}

struct CacheEntry {
    value: String,
    expires_at: Instant,
}

impl Cache {
    pub fn new() -> Self {
        Self {
            data: Arc::new(RwLock::new(HashMap::new())),
        }
    }
    
    pub async fn get(&self, key: &str) -> Option<String> {
        let data = self.data.read().await;
        data.get(key)
            .filter(|entry| entry.expires_at > Instant::now())
            .map(|entry| entry.value.clone())
    }
    
    pub async fn set(&self, key: String, value: String, ttl: Duration) {
        let mut data = self.data.write().await;
        data.insert(key, CacheEntry {
            value,
            expires_at: Instant::now() + ttl,
        });
    }
    
    pub async fn delete(&self, key: &str) {
        let mut data = self.data.write().await;
        data.remove(key);
    }
}

使用缓存 #

rust
use std::time::Duration;

#[get("/cached/<key>")]
async fn get_cached(key: &str, cache: &State<Cache>) -> String {
    match cache.get(key).await {
        Some(value) => format!("Cached: {}", value),
        None => {
            let value = format!("value-for-{}", key);
            cache.set(key.to_string(), value.clone(), Duration::from_secs(60)).await;
            format!("New: {}", value)
        }
    }
}

请求本地状态 #

使用local_cache #

rust
use rocket::request::Request;

#[get("/compute")]
fn compute(request: &Request<'_>) -> String {
    let result = request.local_cache(|| {
        expensive_computation()
    });
    format!("Result: {}", result)
}

fn expensive_computation() -> String {
    "computed-value".to_string()
}

完整示例 #

rust
#[macro_use] extern crate rocket;

use rocket::State;
use std::sync::Mutex;
use std::collections::HashMap;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;

#[derive(Debug, Clone)]
struct Config {
    app_name: String,
    version: String,
}

struct Cache {
    data: RwLock<HashMap<String, (String, Instant)>>,
}

impl Cache {
    fn new() -> Self {
        Self {
            data: RwLock::new(HashMap::new()),
        }
    }
    
    async fn get(&self, key: &str) -> Option<String> {
        let data = self.data.read().await;
        data.get(key)
            .filter(|(_, expires)| expires > &Instant::now())
            .map(|(value, _)| value.clone())
    }
    
    async fn set(&self, key: String, value: String, ttl: Duration) {
        let mut data = self.data.write().await;
        data.insert(key, (value, Instant::now() + ttl));
    }
}

struct Db {
    users: Mutex<HashMap<u32, User>>,
}

#[derive(Debug, Clone, rocket::serde::Serialize, rocket::serde::Deserialize)]
#[serde(crate = "rocket::serde")]
struct User {
    id: u32,
    name: String,
    email: String,
}

impl Db {
    fn new() -> Self {
        let mut users = HashMap::new();
        users.insert(1, User { id: 1, name: "Alice".to_string(), email: "alice@example.com".to_string() });
        users.insert(2, User { id: 2, name: "Bob".to_string(), email: "bob@example.com".to_string() });
        
        Self {
            users: Mutex::new(users),
        }
    }
    
    fn get_user(&self, id: u32) -> Option<User> {
        let users = self.users.lock().unwrap();
        users.get(&id).cloned()
    }
    
    fn create_user(&self, user: User) -> User {
        let mut users = self.users.lock().unwrap();
        let id = users.len() as u32 + 1;
        let user = User { id, ..user };
        users.insert(id, user.clone());
        user
    }
    
    fn list_users(&self) -> Vec<User> {
        let users = self.users.lock().unwrap();
        users.values().cloned().collect()
    }
}

#[get("/")]
fn index(config: &State<Config>) -> String {
    format!("{} v{}", config.app_name, config.version)
}

#[get("/users")]
fn list_users(db: &State<Db>) -> rocket::serde::json::Json<Vec<User>> {
    rocket::serde::json::Json(db.list_users())
}

#[get("/users/<id>")]
async fn get_user(id: u32, db: &State<Db>, cache: &State<Cache>) -> Option<rocket::serde::json::Json<User>> {
    let cache_key = format!("user:{}", id);
    
    if let Some(cached) = cache.get(&cache_key).await {
        println!("Cache hit for user {}", id);
    }
    
    db.get_user(id).map(rocket::serde::json::Json)
}

#[post("/users", format = "json", data = "<user>")]
fn create_user(user: rocket::serde::json::Json<User>, db: &State<Db>) -> rocket::serde::json::Json<User> {
    let created = db.create_user(user.into_inner());
    rocket::serde::json::Json(created)
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .manage(Config {
            app_name: "Rocket API".to_string(),
            version: "1.0.0".to_string(),
        })
        .manage(Db::new())
        .manage(Cache::new())
        .mount("/api", routes![index, list_users, get_user, create_user])
}

下一步 #

掌握了状态管理后,让我们继续学习 数据库概述,了解Rocket与数据库的集成方式。

最后更新:2026-03-28