自定义中间件
中间件结构
自定义中间件需要实现 MiddleWareHandler trait:
use silent::prelude::*;
struct MyMiddleware;
#[async_trait]
impl MiddleWareHandler for MyMiddleware {
async fn handle(&self, req: Request, next: &Next) -> Result<Response> {
// 前置处理
println!("Before request: {}", req.uri());
// 调用下一个中间件或处理器
let res = next.call(req).await?;
// 后置处理
println!("After request: {}", res.status());
Ok(res)
}
}中间件生命周期
中间件在请求处理过程中遵循以下生命周期:
前置处理:在请求到达下一个处理器之前执行
调用下一个处理器:通过
next.call(req)传递请求后置处理:在获得响应后执行
返回处理后的响应
示例:请求计时中间件
use std::time::Instant;
use silent::prelude::*;
struct TimingMiddleware;
#[async_trait]
impl MiddleWareHandler for TimingMiddleware {
async fn handle(&self, req: Request, next: &Next) -> Result<Response> {
let start = Instant::now();
let res = next.call(req).await?;
let duration = start.elapsed();
println!("Request took: {:?}", duration);
Ok(res)
}
}注册使用
let route = Route::new("")
.hook(TimingMiddleware)
.get(handler);中间件执行顺序
中间件按照注册顺序形成处理链,遵循"洋葱模型":
请求按注册顺序从外到内经过每个中间件的前置处理
到达最终的处理函数
响应按相反顺序从内到外经过每个中间件的后置处理
let route = Route::new("")
.hook(LogMiddleware) // 最先执行前置处理,最后执行后置处理
.hook(AuthMiddleware) // 第二个执行前置处理,倒数第二个执行后置处理
.hook(TimingMiddleware) // 最后执行前置处理,最先执行后置处理
.get(handler); // 处理函数最佳实践
保持中间件职责单一,每个中间件只负责一个特定功能
避免在中间件中进行耗时操作,可能会影响整个请求的响应时间
正确处理错误,使用
Result类型返回错误信息合理安排中间件执行顺序,将通用处理(如日志)放在外层,特定处理(如认证)放在内层
注意中间件的状态管理,如果需要共享状态,确保使用适当的同步机制
在开发中间件时注意性能影响,可以通过性能分析工具评估中间件的开销
Last updated
Was this helpful?