导语
用Rust开发后台管理系统时,最常纠结的就是选Axum还是Actix-web。两个框架性能都严重过剩,真正的差距在开发效率、代码维护、生态集成这些“软实力”上。本文将结合管理软件典型场景(认证、中间件、错误处理等),通过5个维度的实战对比,帮你一针见血地做出选择。
文章目录
一、背景:为什么会有这场“框架之争”?
Rust Web 生态经过多年发展,已经收敛到两大主流异步框架:
- Actix-web:老牌劲旅,社区庞大,概念丰富(App、Resource、Guard、Middleware),文档教程铺天盖地。
- Axum:Tokio 团队亲儿子,基于 Tower/Hyper 构建,函数式、类型安全,近年来热度飙升,已成为新项目首选。
对于管理软件(后台管理系统、ERP、CRM、内部工具)来说,二者都能轻松扛住每秒数万请求,性能早已不是瓶颈。我们真正需要比较的是:谁能更快地把业务逻辑写对、写好、写稳。
二、核心维度对比(附可运行代码片段)
2.1 认证与授权
管理软件的第一个门槛就是登录态与角色校验。
Actix-web:现成的积木
Actix-web 生态提供了 actix-session(服务端会话)、actix-identity(登录用户抽象)以及 actix-web-httpauth。搭一套“用户名+密码 → session cookie → 权限中间件”非常快。
// Cargo.toml (actix-web 4)
[dependencies]
actix-web = "4"
actix-session = { version = "0.9", features = ["cookie-session"] }
actix-identity = "0.7"
// main.rs
use actix_web::{web, App, HttpServer, HttpResponse, middleware};
use actix_session::Session;
use actix_identity::Identity;
use actix_web::FromRequest;
async fn login(
user: Option<Identity>, // 自动提取已登录用户
session: Session,
) -> HttpResponse {
if let Some(user) = user {
return HttpResponse::Ok().body("已登录");
}
// 验证逻辑...
user.remember("user_id".to_string());
HttpResponse::Ok().body("登录成功")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.wrap(middleware::Logger::default())
// 一行启用身份管理
.wrap(IdentityService::new(IdentityPolicy::default()))
.route("/login", web::post().to(login))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
✅ 优点:开箱即用,复制粘贴即可工作。
⚠️ 缺点:概念耦合,后期想改成 JWT 或自定义鉴权需要较大改动。
Axum:灵活但需手工组装
Axum 没有内置身份抽象,需要配合 tower-sessions 或手动实现提取器。
// Cargo.toml (axum 0.7)
[dependencies]
axum = "0.7"
tower-sessions = "0.11"
tower-http = { version = "0.5", features = ["auth"] }
// extractors/auth.rs
use axum::{
extract::FromRequestParts,
http::request::Parts,
async_trait,
};
use tower_sessions::Session;
pub struct CurrentUser(pub String);
#[async_trait]
impl<S> FromRequestParts<S> for CurrentUser
where
S: Send + Sync,
{
type Rejection = (axum::http::StatusCode, String);
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let session = Session::from_request_parts(parts, state).await
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "session error".into()))?;
let user_id: Option<String> = session.get("user_id").await.unwrap_or(None);
user_id.map(CurrentUser).ok_or((StatusCode::UNAUTHORIZED, "请先登录".into()))
}
}
// main.rs
use axum::{Router, routing::get, Extension};
use tower_sessions::{SessionManagerLayer, cookie::Key};
async fn dashboard(user: CurrentUser) -> String {
format!("欢迎, {}", user.0)
}
#[tokio::main]
async fn main() {
let session_store = // 配置 Redis/Postgres 存储
let router = Router::new()
.route("/dashboard", get(dashboard))
.layer(SessionManagerLayer::new(session_store).with_secure(false));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, router).await.unwrap();
}
✅ 优点:完全掌控鉴权流程,与 Tower 生态无缝集成。
⚠️ 缺点:需要多写一些样板代码,对新手不够友好。
💡 小结
- 追求“30分钟出登录” → Actix-web
- 需要自定义复杂鉴权(多级权限、JWT+Session混合) → Axum
2.2 中间件体系
管理软件重度依赖日志、跨域、压缩、限流、操作审计等中间件。
| 能力 | Actix-web | Axum (基于 Tower) |
|---|---|---|
| 内置中间件 | Logger, CORS, Compress 等 | 需引入 tower-http |
| 自定义中间件复杂度 | 实现 Transform + Service,样板代码多 | 实现 Layer + Service,更直观 |
| 组合方式 | wrap() / wrap_fn() | .layer() 链式叠加,清晰易读 |
实战中,Axum 的中间件模型完胜。比如要用一个记录每个请求执行时间的审计中间件:
// 一个 Tower Layer 的实现(axum)
use std::time::Instant;
use tower::{Layer, Service};
#[derive(Clone)]
pub struct TimingLayer;
impl<S> Layer<S> for TimingLayer {
type Service = TimingMiddleware<S>;
fn layer(&self, inner: S) -> Self::Service {
TimingMiddleware { inner }
}
}
pub struct TimingMiddleware<S> { inner: S }
impl<S, Req> Service<Req> for TimingMiddleware<S>
where
S: Service<Req>,
{
type Response = S::Response;
type Error = S::Error;
type Future = // 略...
fn poll_ready(/* */) -> /* */ { self.inner.poll_ready(cx) }
fn call(&self, req: Req) -> Self::Future {
let start = Instant::now();
let future = self.inner.call(req);
async move {
let response = future.await?;
let elapsed = start.elapsed();
println!("请求耗时: {:?}", elapsed);
Ok(response)
}
}
}
// 使用:.layer(TimingLayer)
这样的自定义中间件,在 Actix-web 里需要实现两个 trait 并处理 poll_ready 细节,门槛明显更高。
💡 小结:如果你的系统会频繁编写业务相关中间件(如操作审计),Axum 能大幅降低后期维护成本。
2.3 错误处理与响应一致性
管理软件要求统一的错误码和 JSON 响应结构。
Axum 的做法非常“Rusty”:让自定义错误实现 IntoResponse。
use axum::response::{IntoResponse, Response};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("资源未找到")]
NotFound,
#[error("权限不足")]
Forbidden,
#[error(transparent)]
Internal(#[from] anyhow::Error),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, code, msg) = match self {
AppError::NotFound => (StatusCode::NOT_FOUND, 40401, "资源未找到"),
AppError::Forbidden => (StatusCode::FORBIDDEN, 40301, "权限不足"),
AppError::Internal(e) => (StatusCode::INTERNAL_SERVER_ERROR, 50000, &format!("内部错误: {e}")),
};
let body = serde_json::json!({ "code": code, "msg": msg });
(status, axum::Json(body)).into_response()
}
}
// 在handler中直接返回 AppError 即可
async fn get_user() -> Result<Json<User>, AppError> {
let user = find_user().ok_or(AppError::NotFound)?;
Ok(Json(user))
}
Actix-web 则需要实现 ResponseError trait,并返回 actix_web::Error。虽然也能达到同样效果,但错误类型与框架绑定更紧密,而且引入 anyhow 等外部错误库时,需要额外适配。
💡 小结:错误处理上,Axum 的代码更清晰、更解耦,非常适合大型项目。
2.4 数据库与 ORM 集成
两个框架都完美支持 sqlx、diesel、sea-orm。管理软件常用连接池 sqlx::PgPool。
| 框架 | 状态共享方式 | 示例代码 |
|---|---|---|
| Axum | axum::Extension 或 State | .with_state(pool) |
| Actix-web | web::Data | .app_data(web::Data::new(pool)) |
// Axum 示例 (main.rs)
let pool = sqlx::PgPool::connect("...").await?;
let app = Router::new()
.route("/users", get(list_users))
.with_state(pool);
async fn list_users(
State(pool): State<PgPool>,
) -> Result<Json<Vec<User>>, AppError> {
let users = sqlx::query_as!(User, "SELECT id, name FROM users")
.fetch_all(&pool)
.await?;
Ok(Json(users))
}
// Actix-web 示例
async fn list_users(pool: web::Data<PgPool>) -> Result<HttpResponse, Error> {
let users = sqlx::query_as!(User, "SELECT ...")
.fetch_all(pool.get_ref())
.await
.map_err(actix_web::error::ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(users))
}
💡 小结:数据库层面两者几乎无差别,选你喜欢的 ORM 就行。
2.5 学习曲线与团队上手
- Actix-web:概念多(Resource, Scope, Guard, HttpRequest 手动提取),但教程海量,适合新手“照猫画虎”。
- Axum:概念少(Router, Extractor, Layer),本质就是函数+类型,更符合现代 Rust 风格。但因为官方不提供一站式解决方案,遇到鉴权/模板等需求需要自己找 crate 组合,知识广度要求更高。
三、选型决策树(一图胜千言)
| 典型场景 | 推荐框架 | 理由 |
|---|---|---|
| 小型内部工具、一天出活 | Actix-web | 复制粘贴即可搞定登录+session |
| 中大型管理系统、需持续演进 | Axum | 代码维护性更优,Tower中间件复用性强 |
| 已有 Actix-web 技术积累 | Actix-web | 团队熟练度优先,避免迁移成本 |
| 全新项目,希望与 Tokio 生态对齐 | Axum | 社区趋势明显,长期更稳定 |
四、踩坑记录与常见问题 FAQ
4.1 Actix-web 的状态共享“陷阱”
问题:新手容易把 web::Data 和 App::app_data() 搞混,导致运行时 MissingAppData 错误。
✅ 解决:web::Data<T> 用于 extractor,但必须先在 App 上使用 .app_data(web::Data::new(...)) 注册。
4.2 Axum 的 Extractor 顺序引发 500
问题:如果你写的 FromRequestParts 实现中意外 panic 或者返回 Rejection 不当,Axum 默认返回 500。
✅ 解决:自定义 extractor 应尽可能捕获错误并返回语义化的 StatusCode,比如登录失败返回 401。
4.3 我的项目里既有同步阻塞任务怎么办?
⚠️ 两个框架都是异步的,执行阻塞操作(如大量 CPU 计算)会饿死事件循环。
🚀 推荐:使用 tokio::task::spawn_blocking 把阻塞任务丢进专有线程池。
五、总结
选择 Axum 还是 Actix-web,本质上是选择开发哲学和生态站位:
- Actix-web:大而全的“瑞士军刀”,快速启动的利器。
- Axum:小而美的“乐高积木”,长期维护的基石。
对于管理软件而言,如果你需要的是一个今天就能跑、明天就能交付的原型,Actix-web 不会让你失望;如果你做的是一个要维护五年、不断加入新特性的核心系统,Axum 带来的架构可扩展性和代码美感,绝对值得你投入。
最后,建议两个框架的 Hello World 都写一遍,用身体感受哪种风格更让你愿意每天打开 VSCode。
如果本文对你有帮助,欢迎点赞👍、收藏⭐、关注🔔!你更喜欢用哪个框架开发管理系统?欢迎在评论区交流💬。
标签: Rust, Axum, Actix-web, Web框架, 管理软件, 选型指南, 后台开发, Tokio, 中间件, 性能优化
1009

被折叠的 条评论
为什么被折叠?



