首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Rust Tokio 入门:构建高性能 Web 服务:Axum + Tokio 实战

Rust Tokio 入门:构建高性能 Web 服务:Axum + Tokio 实战

作者头像
不吃草的牛德
发布2026-04-23 13:01:40
发布2026-04-23 13:01:40
1490
举报
文章被收录于专栏:RustRust

Tokio 系列第七篇重磅更新!

前六篇我们从 Runtime、Channel、Stream 到网络基础,已经为高并发打下坚实基础。今天我们进入Web 服务实战 —— 使用 Axum + Tokio 构建高性能 Web 服务。

为什么选择 Axum?

  • • 由 Tokio 团队维护,与 Tokio 深度集成
  • • 基于 Tower 中间件生态,模块化、可组合
  • • 类型安全极强,提取器(Extractor)设计优雅
  • • 性能优秀(2026 年与 Actix Web 差距很小,但维护性和生态更好)
  • • 支持 REST、WebSocket、静态文件、gRPC 等,几乎覆盖所有场景

本篇我们将一步步构建一个带认证的 TODO API,并添加WebSocket 实时同步功能,让你直接获得生产级项目模板。

一、项目初始化与依赖配置

创建项目:

代码语言:javascript
复制
cargo new axum-todo --bin
cd axum-todo

Cargo.toml(推荐生产配置):

代码语言:javascript
复制
[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"
二、应用状态共享(State)

高性能 Web 服务通常需要共享状态(如数据库连接池、配置、广播通道):

代码语言:javascript
复制
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 等连接池。

三、路由与 Handler 编写(核心)
代码语言:javascript
复制
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();
}
四、组装 Router(模块化路由)
代码语言:javascript
复制
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 Runtime)
代码语言:javascript
复制
#[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 测试。

测试工具推荐:使用 curlPostmanhttpie

六、生产级最佳实践
  1. 1. 中间件栈(Tower 生态优势):
    • TraceLayer:自动日志
    • CompressionLayer:gzip/br 压缩
    • TimeoutLayer:防止慢请求占用资源
    • RateLimitLayer:限流
  2. 2. 错误处理:统一使用 axum::response::IntoResponse + 自定义错误类型 + thiserror
  3. 3. 状态共享:复杂场景用 Arc<dashmap::DashMap>tokio::sync::RwLock
  4. 4. 数据库集成:强烈推荐 sqlx(编译时检查 SQL) + 连接池。
  5. 5. 优雅关闭:使用 tokio::signal 监听 Ctrl+C,实现 graceful shutdown。
  6. 6. 性能调优
    • • 使用上一期学到的 Runtime 配置(合理 worker_threads)
    • • 开启 tower-http 的压缩和 tracing
    • • 生产部署推荐 Docker + 多核绑定
  7. 7. WebSocket 注意事项
    • • 每个连接独立 Task
    • • 使用 broadcast 通道实现高效广播
    • • 结合 select! 处理读写与心跳
七、完整项目结构建议(生产推荐)
代码语言:javascript
复制
src/
├── main.rs
├── router.rs          # 路由组装
├── handlers/
│   ├── todo.rs
│   └── ws.rs
├── state.rs           # AppState 定义
├── models.rs          # Todo、User 等模型
└── error.rs           # 统一错误处理
八、总结

Axum + Tokio 是 2026 年构建高性能 Rust Web 服务的黄金组合

  • • 代码简洁、类型安全
  • • 中间件复用性极高
  • • 与 Tokio 生态无缝衔接(Channel、Stream、Runtime 全部可用)

通过本篇,你已经可以快速搭建一个支持 REST + WebSocket 的高并发服务,性能轻松达到 Go/FastAPI 级别,同时拥有 Rust 的内存安全。

我们下期见!

(完)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rust火箭工坊 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、项目初始化与依赖配置
  • 二、应用状态共享(State)
  • 三、路由与 Handler 编写(核心)
  • 四、组装 Router(模块化路由)
  • 五、主函数与优雅启动(结合 Tokio Runtime)
  • 六、生产级最佳实践
  • 七、完整项目结构建议(生产推荐)
  • 八、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档