
Tokio 系列第七篇重磅更新!
前六篇我们从 Runtime、Channel、Stream 到网络基础,已经为高并发打下坚实基础。今天我们进入Web 服务实战 —— 使用 Axum + Tokio 构建高性能 Web 服务。
为什么选择 Axum?
本篇我们将一步步构建一个带认证的 TODO API,并添加WebSocket 实时同步功能,让你直接获得生产级项目模板。
创建项目:
cargo new axum-todo --bin
cd axum-todoCargo.toml(推荐生产配置):
[package]
name = "axum-todo"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = { version = "0.8", features = ["ws", "json"] } # 0.8 是 2026 年主流
tokio = { version = "1", features = ["full"] }
tower-http = { version = "0.6", features = ["trace", "cors", "compression-full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
uuid = { version = "1.0", features = ["v4", "serde"] }
futures-util = "0.3.32"高性能 Web 服务通常需要共享状态(如数据库连接池、配置、广播通道):
use std::sync::Arc;
use tokio::sync::broadcast;
#[derive(Clone)]
struct AppState {
todo_db: Arc<tokio::sync::Mutex<Vec<Todo>>>, // 简单内存存储,生产换 sqlx + Pool
tx: broadcast::Sender<String>, // WebSocket 广播
}
#[derive(Clone, serde::Serialize, serde::Deserialize)]
struct Todo {
id: uuid::Uuid,
title: String,
completed: bool,
}生产推荐使用 Arc<sqlx::PgPool> 或 deadpool 等连接池。
use axum::{
extract::{Path, State, Json, ws::{WebSocketUpgrade, WebSocket, Message}},
http::StatusCode,
response::IntoResponse,
routing::{get, post, put, delete},
Router,
};
use std::sync::Arc;
use futures_util::{StreamExt,SinkExt};
async fn root() -> &'static str {
"Axum + Tokio TODO API 运行中!"
}
// 获取所有 TODO
async fn get_todos(State(state): State<Arc<AppState>>) -> Json<Vec<Todo>> {
let todos = state.todo_db.lock().await;
Json(todos.clone())
}
// 创建 TODO
async fn create_todo(
State(state): State<Arc<AppState>>,
Json(payload): Json<Todo>,
) -> (StatusCode, Json<Todo>) {
let mut todos = state.todo_db.lock().await;
let new_todo = Todo { id: uuid::Uuid::new_v4(), ..payload };
todos.push(new_todo.clone());
// 广播给 WebSocket 客户端
let _ = state.tx.send(serde_json::to_string(&new_todo).unwrap());
(StatusCode::CREATED, Json(new_todo))
}
// WebSocket 实时同步
async fn ws_handler(
ws: WebSocketUpgrade,
State(state): State<Arc<AppState>>,
) -> impl IntoResponse {
ws.on_upgrade(|socket| handle_socket(socket, state))
}
async fn handle_socket(mut socket: WebSocket, state: Arc<AppState>) {
let mut rx = state.tx.subscribe();
let (mut sender, mut receiver) = socket.split();
// 转发广播消息给客户端
let broadcast_task = tokio::spawn(async move {
while let Ok(msg) = rx.recv().await {
if sender.send(Message::Text(msg.into())).await.is_err() {
break;
}
}
});
// 处理客户端发来的消息(可选)
while let Some(Ok(msg)) = receiver.next().await {
// 可根据业务处理客户端消息
}
broadcast_task.abort();
}fn create_router(state: Arc<AppState>) -> Router {
Router::new()
.route("/", get(root))
.route("/todos", get(get_todos).post(create_todo))
// .route("/todos/:id", put(update_todo).delete(delete_todo)) // 可继续扩展
.route("/ws", get(ws_handler))
.layer(tower_http::trace::TraceLayer::new_for_http()) // 请求日志
.layer(tower_http::cors::CorsLayer::permissive()) // 开发阶段放开 CORS
.with_state(state)
}#[tokio::main]
async fn main() {
// 初始化 tracing
tracing_subscriber::fmt::init();
let (tx, _) = broadcast::channel(100);
let state = Arc::new(AppState {
todo_db: Arc::new(tokio::sync::Mutex::new(vec![])),
tx,
});
let app = create_router(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
println!("🚀 Axum 服务启动成功,监听 http://127.0.0.1:3000");
axum::serve(listener, app).await.unwrap();
}运行 cargo run,访问 http://127.0.0.1:3000/todos 测试。
测试工具推荐:使用 curl、Postman 或 httpie。
TraceLayer:自动日志CompressionLayer:gzip/br 压缩TimeoutLayer:防止慢请求占用资源RateLimitLayer:限流axum::response::IntoResponse + 自定义错误类型 + thiserror。Arc<dashmap::DashMap> 或 tokio::sync::RwLock。sqlx(编译时检查 SQL) + 连接池。tokio::signal 监听 Ctrl+C,实现 graceful shutdown。tower-http 的压缩和 tracingbroadcast 通道实现高效广播select! 处理读写与心跳src/
├── main.rs
├── router.rs # 路由组装
├── handlers/
│ ├── todo.rs
│ └── ws.rs
├── state.rs # AppState 定义
├── models.rs # Todo、User 等模型
└── error.rs # 统一错误处理Axum + Tokio 是 2026 年构建高性能 Rust Web 服务的黄金组合:
通过本篇,你已经可以快速搭建一个支持 REST + WebSocket 的高并发服务,性能轻松达到 Go/FastAPI 级别,同时拥有 Rust 的内存安全。
我们下期见!
(完)