应用状态 #

什么是应用状态? #

应用状态是在整个应用程序中共享的数据。Actix Web 通过 web::Data 提供状态管理功能。

text
┌─────────────────────────────────────────────────────────────┐
│                      应用状态架构                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              HttpServer                              │   │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐             │   │
│  │  │ Worker 1│  │ Worker 2│  │ Worker N│             │   │
│  │  │         │  │         │  │         │             │   │
│  │  │ App     │  │ App     │  │ App     │             │   │
│  │  │ State   │  │ State   │  │ State   │             │   │
│  │  └─────────┘  └─────────┘  └─────────┘             │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                              │
│  状态通过 Arc 共享,每个 Worker 有自己的 App 实例            │
│                                                              │
└─────────────────────────────────────────────────────────────┘

基本用法 #

定义状态结构体 #

rust
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Mutex;

pub struct AppState {
    pub request_count: AtomicU64,
    pub users: Mutex<Vec<String>>,
}

注册状态 #

rust
use actix_web::{web, App, HttpServer};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let state = web::Data::new(AppState {
        request_count: AtomicU64::new(0),
        users: Mutex::new(Vec::new()),
    });
    
    HttpServer::new(move || {
        App::new()
            .app_data(state.clone())
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

在处理函数中使用 #

rust
use actix_web::{web, Responder};
use std::sync::atomic::Ordering;

#[actix_web::get("/count")]
async fn get_count(state: web::Data<AppState>) -> impl Responder {
    let count = state.request_count.load(Ordering::SeqCst);
    web::Json(serde_json::json!({ "count": count }))
}

#[actix_web::post("/increment")]
async fn increment(state: web::Data<AppState>) -> impl Responder {
    state.request_count.fetch_add(1, Ordering::SeqCst);
    web::Json(serde_json::json!({ "success": true }))
}

状态类型 #

原子类型 #

rust
use std::sync::atomic::{AtomicU64, AtomicBool, Ordering};

pub struct AppState {
    pub request_count: AtomicU64,
    pub is_maintenance: AtomicBool,
}

#[actix_web::get("/status")]
async fn status(state: web::Data<AppState>) -> impl Responder {
    web::Json(serde_json::json!({
        "requests": state.request_count.load(Ordering::SeqCst),
        "maintenance": state.is_maintenance.load(Ordering::SeqCst)
    }))
}

Mutex 包装类型 #

rust
use std::sync::Mutex;

pub struct AppState {
    pub cache: Mutex<std::collections::HashMap<String, String>>,
}

#[actix_web::get("/cache/{key}")]
async fn get_cache(
    path: web::Path<String>,
    state: web::Data<AppState>,
) -> impl Responder {
    let key = path.into_inner();
    let cache = state.cache.lock().unwrap();
    
    match cache.get(&key) {
        Some(value) => web::Json(serde_json::json!({ "value": value })),
        None => web::Json(serde_json::json!({ "error": "Not found" })),
    }
}

RwLock 包装类型 #

rust
use std::sync::RwLock;

pub struct AppState {
    pub config: RwLock<Config>,
}

#[derive(Clone)]
pub struct Config {
    pub debug: bool,
    pub max_connections: u32,
}

#[actix_web::get("/config")]
async fn get_config(state: web::Data<AppState>) -> impl Responder {
    let config = state.config.read().unwrap();
    web::Json(serde_json::json!({
        "debug": config.debug,
        "max_connections": config.max_connections
    }))
}

#[actix_web::put("/config")]
async fn update_config(
    state: web::Data<AppState>,
    body: web::Json<Config>,
) -> impl Responder {
    let mut config = state.config.write().unwrap();
    *config = body.into_inner();
    web::Json(serde_json::json!({ "success": true }))
}

多个状态 #

注册多个状态 #

rust
pub struct DbPool {
    // 数据库连接池
}

pub struct Cache {
    // 缓存
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let db_pool = web::Data::new(DbPool { /* ... */ });
    let cache = web::Data::new(Cache { /* ... */ });
    
    HttpServer::new(move || {
        App::new()
            .app_data(db_pool.clone())
            .app_data(cache.clone())
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

使用多个状态 #

rust
#[actix_web::get("/users/{id}")]
async fn get_user(
    path: web::Path<u32>,
    db: web::Data<DbPool>,
    cache: web::Data<Cache>,
) -> impl Responder {
    // 使用 db 和 cache
    web::Json(serde_json::json!({ "id": path.into_inner() }))
}

状态作用域 #

应用级别 #

rust
App::new()
    .app_data(state)  // 所有路由可用

范围级别 #

rust
App::new()
    .service(
        web::scope("/api")
            .app_data(api_state)
            .route("/users", web::get().to(get_users))
    )

状态初始化 #

异步初始化 #

rust
use sqlx::postgres::PgPoolOptions;

pub struct AppState {
    pub db: sqlx::PgPool,
}

impl AppState {
    pub async fn new(database_url: &str) -> Self {
        let db = PgPoolOptions::new()
            .max_connections(5)
            .connect(database_url)
            .await
            .expect("Failed to create pool");
        
        Self { db }
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let database_url = std::env::var("DATABASE_URL").unwrap();
    let state = web::Data::new(AppState::new(&database_url).await);
    
    HttpServer::new(move || {
        App::new()
            .app_data(state.clone())
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

完整示例 #

rust
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
    id: u64,
    name: String,
    email: String,
}

struct AppState {
    next_id: AtomicU64,
    users: Mutex<HashMap<u64, User>>,
}

impl AppState {
    fn new() -> Self {
        Self {
            next_id: AtomicU64::new(1),
            users: Mutex::new(HashMap::new()),
        }
    }
}

#[derive(Deserialize)]
struct CreateUser {
    name: String,
    email: String,
}

#[actix_web::get("/users")]
async fn list_users(state: web::Data<Arc<AppState>>) -> impl Responder {
    let users = state.users.lock().unwrap();
    let users: Vec<&User> = users.values().collect();
    HttpResponse::Ok().json(users)
}

#[actix_web::get("/users/{id}")]
async fn get_user(
    path: web::Path<u64>,
    state: web::Data<Arc<AppState>>,
) -> impl Responder {
    let users = state.users.lock().unwrap();
    
    match users.get(&path.into_inner()) {
        Some(user) => HttpResponse::Ok().json(user),
        None => HttpResponse::NotFound().json(serde_json::json!({
            "error": "User not found"
        })),
    }
}

#[actix_web::post("/users")]
async fn create_user(
    body: web::Json<CreateUser>,
    state: web::Data<Arc<AppState>>,
) -> impl Responder {
    let id = state.next_id.fetch_add(1, Ordering::SeqCst);
    
    let user = User {
        id,
        name: body.name.clone(),
        email: body.email.clone(),
    };
    
    state.users.lock().unwrap().insert(id, user.clone());
    
    HttpResponse::Created().json(user)
}

#[actix_web::delete("/users/{id}")]
async fn delete_user(
    path: web::Path<u64>,
    state: web::Data<Arc<AppState>>,
) -> impl Responder {
    let mut users = state.users.lock().unwrap();
    
    match users.remove(&path.into_inner()) {
        Some(_) => HttpResponse::NoContent().finish(),
        None => HttpResponse::NotFound().json(serde_json::json!({
            "error": "User not found"
        })),
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let state = Arc::new(AppState::new());
    
    println!("Server running at http://127.0.0.1:8080");
    
    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(state.clone()))
            .service(list_users)
            .service(get_user)
            .service(create_user)
            .service(delete_user)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

下一步 #

现在你已经掌握了应用状态,继续学习 数据共享,深入了解数据共享机制!

最后更新:2026-03-29