全书目录

第三十九篇:Axum 完全指南 —— Rust 类型关口宇宙

第八章:State 是什么 —— 它是总关底册,不是每辆车自己的临时纸条

2 分钟 458 字 第 754 / 962 个阅读单元

在 Axum 里,共享状态最推荐的方式是 State<T>

rust
use axum::{extract::State, routing::get, Router};
use std::sync::Arc;

#[derive(Clone)]
struct AppState {
    service_name: String,
}

async fn health(State(state): State<Arc<AppState>>) -> String {
    format!("{} OK", state.service_name)
}

let shared_state = Arc::new(AppState {
    service_name: "north-gate".to_owned(),
});

let app = Router::new()
    .route("/health", get(health))
    .with_state(shared_state);

这张图很重要:

text
State
= 整座总关共享的底册
= 每个请求都能查
= 适合放数据库连接池、配置、客户端、缓存句柄

但官方文档也明确提醒了一件很容易踩坑的事:

with_state 提供的是全局状态,不适合放“从请求里临时提取出来的数据”,比如鉴权后的当前用户。那类数据应该放 Extension

也就是说:

text
总关底册(全局共享)
-> State

某辆车本次通关时临时贴上的标签
-> Extension

比如:

  • State<AppState>:数据库池、配置、Redis 客户端
  • Extension<AuthContext>:当前关员、当前租户、当前请求 trace 数据
#一个进阶细节:Router<S> 不是“拥有状态 S”,而是“还缺状态 S”

这点是 Axum 新手高频误区。

很多人看到 Router<AppState> 会以为是“这个 router 已经有了 AppState”。

其实更准确的意思是:

text
Router<AppState>
= 这张关口图要真正接车,还缺一个 AppState

所以:

  • 先写 fn routes() -> Router<AppState> 很常见
  • 最后在 main.with_state(app_state) 再落地,很正常

这个心智一旦顺了,你对 nestmerge、模块化路由的理解会轻很多。