跳到主要内容

中间件设计

问题

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)ExpressKoa
类型安全编译时检查运行时运行时
组合方式Layer 嵌套use() 链式洋葱模型
异步模型Future 组合回调/Promiseasync/await
性能零成本(内联)有 V8 开销有 V8 开销

Tower 中间件通过类型系统保证组合安全,错误的中间件组合在编译时就能发现。

相关链接