中间件设计
问题
Rust Web 中间件是如何设计的?
答案
axum 中间件(基于 Tower)
use axum::{
Router, routing::get, middleware,
extract::Request,
response::Response,
http::StatusCode,
};
use std::time::Instant;
// 方式 1:函数式中间件(推荐简单场景)
async fn logging_middleware(
req: Request,
next: middleware::Next,
) -> Response {
let method = req.method().clone();
let uri = req.uri().clone();
let start = Instant::now();
let response = next.run(req).await;
let duration = start.elapsed();
println!("{} {} → {} ({:?})", method, uri, response.status(), duration);
response
}
// 方式 2:认证中间件(带提前返回)
async fn auth_middleware(
req: Request,
next: middleware::Next,
) -> Result<Response, StatusCode> {
let auth_header = req.headers()
.get("Authorization")
.and_then(|v| v.to_str().ok());
match auth_header {
Some(token) if token.starts_with("Bearer ") => {
Ok(next.run(req).await)
}
_ => Err(StatusCode::UNAUTHORIZED),
}
}
// 注册中间件
let app = Router::new()
.route("/api/data", get(handler))
.layer(middleware::from_fn(auth_middleware)) // 先认证
.layer(middleware::from_fn(logging_middleware)); // 再日志
中间件执行顺序
axum 中间件按 .layer() 的反序执行(外层先执行)。后添加的 Layer 实际上包裹在外层。
常用 tower-http 中间件
use tower_http::{
cors::CorsLayer,
compression::CompressionLayer,
trace::TraceLayer,
timeout::TimeoutLayer,
limit::RequestBodyLimitLayer,
};
use std::time::Duration;
let app = Router::new()
.route("/api/data", get(handler))
.layer(CorsLayer::permissive())
.layer(CompressionLayer::new())
.layer(TraceLayer::new_for_http())
.layer(TimeoutLayer::new(Duration::from_secs(30)))
.layer(RequestBodyLimitLayer::new(1024 * 1024)); // 1MB
常见面试问题
Q1: Rust 的中间件和 Express/Koa 有什么区别?
答案:
| 维度 | Rust (Tower) | Express | Koa |
|---|---|---|---|
| 类型安全 | 编译时检查 | 运行时 | 运行时 |
| 组合方式 | Layer 嵌套 | use() 链式 | 洋葱模型 |
| 异步模型 | Future 组合 | 回调/Promise | async/await |
| 性能 | 零成本(内联) | 有 V8 开销 | 有 V8 开销 |
Tower 中间件通过类型系统保证组合安全,错误的中间件组合在编译时就能发现。