Rust 作为一门系统级编程语言,近年来在 Web 开发领域越来越受到关注。其零成本抽象、内存安全和出色的性能特性,使其成为构建高性能 Web 服务的理想选择。本文将带你深入了解如何使用 Rust 的 Axum 框架构建现代化的 Web 应用。
引言
Axum 是由 Tokio 团队开发的 Web 应用框架,它充分利用了 Rust 的异步生态系统。与其他 Rust Web 框架相比,Axum 具有以下优势:
- 与 Tokio、Tower、Hyper 生态无缝集成
- 基于 Tower 的中间件系统,可组合性强
- 类型安全的请求提取器
- 优秀的性能和低延迟
准备工作
在开始之前,请确保你的系统已安装以下工具:
- Rust 1.70+ (推荐使用 rustup 安装)
- Cargo (Rust 的包管理器)
- PostgreSQL 数据库 (可选,用于数据持久化)
项目初始化
首先,创建一个新的 Rust 项目:
cargo new axum-demo
cd axum-demo
在 Cargo.toml 中添加必要的依赖:
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
tower = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
路由设计
Axum 的路由系统非常直观。让我们创建一个简单的路由配置:
use axum::{
routing::{get, post},
Router,
};
#[tokio::main]
async fn main() {
// 初始化日志
tracing_subscriber::init();
// 构建路由
let app = Router::new()
.route("/", get(root))
.route("/users", get(list_users).post(create_user))
.route("/users/:id", get(get_user));
// 启动服务器
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.unwrap();
tracing::info!("Server running on http://localhost:3000");
axum::serve(listener, app)
.await
.unwrap();
}
async fn root() -> &'static str {
"Hello, Axum!"
}
处理器实现
接下来,让我们实现具体的处理器函数:
use axum::{
extract::{Path, Json},
http::StatusCode,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Serialize, Deserialize, Clone)]
struct User {
id: u64,
name: String,
email: String,
}
#[derive(Deserialize)]
struct CreateUserRequest {
name: String,
email: String,
}
async fn list_users() -> Json<Vec<User>> {
let users = vec![
User { id: 1, name: "Alice".to_string(), email: "alice@example.com".to_string() },
User { id: 2, name: "Bob".to_string(), email: "bob@example.com".to_string() },
];
Json(users)
}
async fn get_user(Path(id): Path<u64>) -> Result<Json<User>, StatusCode> {
if id == 1 {
Ok(Json(User {
id: 1,
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
}))
} else {
Err(StatusCode::NOT_FOUND)
}
}
async fn create_user(
Json(payload): Json<CreateUserRequest>,
) -> (StatusCode, Json<User>) {
let user = User {
id: 1337,
name: payload.name,
email: payload.email,
};
(StatusCode::CREATED, Json(user))
}
提示:Axum 的提取器系统非常强大。通过函数参数的类型,Axum 会自动从请求中提取相应的数据。
中间件
使用 Tower 中间件添加日志和超时功能:
use tower::ServiceBuilder;
use tower_http::{
trace::TraceLayer,
cors::CorsLayer,
timeout::TimeoutLayer,
};
use std::time::Duration;
let app = Router::new()
.route("/", get(root))
.layer(
ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
.layer(CorsLayer::permissive())
.layer(TimeoutLayer::new(Duration::from_secs(30)))
);
数据库集成
使用 SQLx 进行异步数据库操作:
use sqlx::PgPool;
#[derive(Clone)]
struct AppState {
db: PgPool,
}
async fn get_user_with_db(
State(state): State<AppState>,
Path(id): Path<i32>,
) -> Result<Json<User>, StatusCode> {
let user = sqlx::query_as!(
User,
"SELECT id, name, email FROM users WHERE id = $1",
id
)
.fetch_one(&state.db)
.await
.map_err(|_| StatusCode::NOT_FOUND)?;
Ok(Json(user))
}
总结
通过本文的介绍,我们了解了如何使用 Rust 和 Axum 构建一个功能完整的 Web 服务。Axum 的简洁设计和强大的类型系统使得开发体验非常愉快。随着 Rust 生态的不断成熟,相信会有越来越多的开发者选择 Rust 作为 Web 开发的首选语言。
如果你想了解更多关于 Rust Web 开发的内容,欢迎关注我的博客,我会持续分享更多实用的技术文章。
写得太好了!正好在学习 Axum,这篇文章帮了大忙。期待更多 Rust 相关的教程!
请问 SQLx 的编译时检查在实际项目中体验如何?会不会增加很多编译时间?
确实会增加一些编译时间,但换来的是运行时的安全性。对于大型项目,建议开启 SQLx 的离线模式,CI 环境会快很多。
收藏了!作为 Rust 新手,感觉 Web 开发的学习曲线还是挺陡的,不过性能确实没得说。