中间件
中间件是 Silent 框架中的重要组成部分,它允许你在请求处理过程中插入自定义逻辑。本文将详细介绍中间件的工作原理、使用方法和最佳实践。
中间件工作原理
在 Silent 中,中间件采用洋葱模型(Onion Model)工作。Next 结构体通过链式结构实现了中间件的调用流程。Next 结构体的核心实现包括:
pub struct Next {
inner: NextInstance,
next: Option<Arc<Next>>,
}
pub(crate) enum NextInstance {
Middleware(Arc<dyn MiddleWareHandler>),
EndPoint(Arc<dyn Handler>),
}中间件的执行流程如下:
请求进入时,通过Next::build方法构建中间件链:
首先创建包含终端处理器(EndPoint)的Next实例,作为链的终点
然后从后向前遍历中间件列表,将每个中间件包装为Next实例
每个Next实例通过Arc智能指针持有下一个节点的引用,形成链式结构
build方法的实现确保了中间件的执行顺序与注册顺序一致
执行时,从最外层中间件开始:
中间件通过实现MiddleWareHandler特征的handle方法处理请求
handle方法接收当前请求(Request)和下一个中间件(Next)作为参数
通过next.call()调用链中的下一个节点,实现请求的传递
可以在next.call()前后添加自定义逻辑,实现请求和响应的处理
当请求到达终端处理器时:
通过Handler特征的call方法处理请求并生成响应
响应沿着中间件链原路返回,实现洋葱模型
每个中间件都可以对响应进行处理,例如添加响应头或修改响应内容
最终响应返回给客户端
│ 请求 │
▼ │
Logger中间件 │
│ │
▼ │
认证中间件 │ 响应
│ │
▼ │
业务处理器 │
│ ▲
└──────────────┘中间件定义
在 Silent 中,中间件是一个实现了 MiddleWareHandler trait 的结构体:
use silent::prelude::*;
pub struct Logger;
#[async_trait]
impl MiddleWareHandler for Logger {
async fn handle(&self, req: Request, next: &Next) -> Result<Response> {
println!("Request: {} {}", req.method(), req.uri());
let start = std::time::Instant::now();
// 调用下一个中间件或处理器
let response = next.call(req).await?;
println!("Response time: {:?}", start.elapsed());
Ok(response)
}
}中间件生命周期
前置处理:在
next.call()之前的代码可以检查和修改请求
可以提前返回响应(如认证失败)
可以添加请求上下文
后置处理:在
next.call()之后的代码可以修改响应
可以记录响应时间
可以进行清理工作
中间件注册
你可以在路由级别注册中间件:
use silent::prelude::*;
// 创建路由并注册中间件
let route = Route::new("")
.hook(Logger::new())
.hook(Authentication::new())
.get(|_req| async { Ok("Hello World") });
// 子路由中间件
let admin = Route::new("admin")
.hook(RequireAdmin::new())
.get(admin_dashboard);中间件的注册顺序决定了它们的执行顺序。在上面的例子中,请求会先经过Logger中间件,然后是Authentication中间件,最后到达处理函数。
// 全局中间件
let app = Route::new("")
.middleware(Logger)
.middleware(Authentication)
.at(api_routes);
// 路由级别中间件
let protected = Route::new("admin")
.middleware(RequireAdmin)
.get(admin_dashboard);常见中间件示例
认证中间件
pub struct Auth;
#[async_trait]
impl MiddleWareHandler for Auth {
async fn handle(&self, mut req: Request, next: &Next) -> Result<Response> {
let token = req.headers()
.get("Authorization")
.ok_or_else(|| Error::new("Missing token")
.with_status(StatusCode::UNAUTHORIZED))?;
// 验证 token
if !verify_token(token) {
return Err(Error::new("Invalid token")
.with_status(StatusCode::UNAUTHORIZED));
}
next.call(req).await
}
}CORS 中间件
pub struct Cors;
#[async_trait]
impl MiddleWareHandler for Cors {
async fn handle(&self, req: Request, next: &Next) -> Result<Response> {
let response = next.call(req).await?;
Ok(response.builder()
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
.header("Access-Control-Allow-Headers", "Content-Type")
.build()?)
}
}请求限流中间件
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{Duration, Instant};
pub struct RateLimit {
count: AtomicUsize,
last_reset: std::sync::Mutex<Instant>,
limit: usize,
window: Duration,
}
impl RateLimit {
pub fn new(limit: usize, window: Duration) -> Self {
Self {
count: AtomicUsize::new(0),
last_reset: std::sync::Mutex::new(Instant::now()),
limit,
window,
}
}
}
#[async_trait]
impl MiddleWareHandler for RateLimit {
async fn handle(&self, req: Request, next: &Next) -> Result<Response> {
let mut last_reset = self.last_reset.lock().unwrap();
if last_reset.elapsed() >= self.window {
self.count.store(0, Ordering::SeqCst);
*last_reset = Instant::now();
}
if self.count.fetch_add(1, Ordering::SeqCst) >= self.limit {
return Err(Error::new("Too many requests")
.with_status(StatusCode::TOO_MANY_REQUESTS));
}
next.call(req).await
}
}中间件链
多个中间件按照注册顺序依次执行:
let app = Route::new("")
.middleware(Logger) // 1. 记录请求
.middleware(Cors) // 2. 处理跨域
.middleware(RateLimit::new(100, Duration::from_secs(60))) // 3. 限流
.at(Route::new("api")
.middleware(Auth) // 4. API 认证
.at(api_routes)
);最佳实践
性能优化
避免阻塞操作
使用异步 IO 操作
将耗时操作放入专门的线程池
合理使用缓存
减少内存分配
复用请求和响应对象
避免不必要的克隆
使用引用而不是拥有权
优化中间件顺序
将频繁使用的中间件放在前面
将耗时的中间件放在必要的位置
错误处理
合理使用错误类型
使用自定义错误类型
提供详细的错误信息
正确设置 HTTP 状态码
优雅降级
提供默认值
实现重试机制
记录错误日志
安全性
输入验证
验证所有用户输入
防止 SQL 注入
防止 XSS 攻击
敏感信息处理
加密敏感数据
不在日志中记录敏感信息
使用安全的会话管理
示例:完整的中间件应用
这是一个包含多个中间件的完整示例:
use silent::prelude::*;
use std::time::Duration;
// 应用配置
let config = AppConfig {
cors_origin: "*".to_string(),
rate_limit: 100,
rate_window: Duration::from_secs(60),
};
// API 路由
let api = Route::new("api")
.middleware(Auth) // API 认证
.at(Route::new("users").get(list_users))
.at(Route::new("posts").get(list_posts));
// 管理员路由
let admin = Route::new("admin")
.middleware(RequireAdmin) // 管理员权限
.at(Route::new("dashboard").get(admin_dashboard));
// 应用程序
let app = Route::new("")
.middleware(Logger) // 请求日志
.middleware(Cors::new(config.cors_origin)) // CORS
.middleware(RateLimit::new( // 限流
config.rate_limit,
config.rate_window,
))
.at(api)
.at(admin);这个示例展示了如何组织一个包含日志记录、跨域处理、限流、认证和权限控制等功能的完整应用程序。中间件的组织结构清晰,便于维护和扩展。
Last updated
Was this helpful?