中间件概念 #

什么是中间件? #

中间件是一种在请求到达处理函数之前和响应返回客户端之后执行代码的机制。它可以用于日志记录、认证、错误处理等场景。

text
┌─────────────────────────────────────────────────────────────┐
│                      中间件执行流程                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  HTTP 请求 ──────────────────────────────────────────────▶  │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              中间件 1 (请求前置处理)                  │   │
│  └─────────────────────────────────────────────────────┘   │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              中间件 2 (请求前置处理)                  │   │
│  └─────────────────────────────────────────────────────┘   │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              处理函数                                 │   │
│  └─────────────────────────────────────────────────────┘   │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              中间件 2 (响应后置处理)                  │   │
│  └─────────────────────────────────────────────────────┘   │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              中间件 1 (响应后置处理)                  │   │
│  └─────────────────────────────────────────────────────┘   │
│         │                                                    │
│         ▼                                                    │
│  ◀───────────────────────────────────────────────────────  │
│  HTTP 响应                                                   │
│                                                              │
└─────────────────────────────────────────────────────────────┘

中间件类型 #

按作用范围分类 #

类型 说明 注册方式
全局中间件 应用于所有请求 App::wrap()
范围中间件 应用于特定范围 Scope::wrap()
资源中间件 应用于特定资源 Resource::wrap()

按功能分类 #

类型 说明 示例
日志中间件 记录请求日志 Logger
认证中间件 验证用户身份 JWT Auth
CORS 中间件 处理跨域请求 Cors
压缩中间件 压缩响应内容 Compress

基本用法 #

注册中间件 #

rust
use actix_web::{middleware, web, App, HttpResponse, HttpServer};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .wrap(middleware::Logger::default())
            .route("/", web::get().to(|| HttpResponse::Ok().body("Hello")))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

中间件执行顺序 #

rust
App::new()
    .wrap(middleware1)  // 最先执行请求前置,最后执行响应后置
    .wrap(middleware2)  // 第二执行请求前置,倒数第二执行响应后置
    .wrap(middleware3)  // 最后执行请求前置,最先执行响应后置

中间件生命周期 #

text
┌─────────────────────────────────────────────────────────────┐
│                    中间件生命周期                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  1. Service::new()                                           │
│     创建中间件服务实例                                        │
│                                                              │
│  2. Service::call()                                          │
│     处理每个请求                                              │
│     │                                                        │
│     ├── 请求前置处理                                          │
│     │   - 修改请求                                            │
│     │   - 添加头部                                            │
│     │   - 验证认证                                            │
│     │                                                        │
│     ├── 调用下一个服务                                        │
│     │   - 传递请求给处理函数                                  │
│     │                                                        │
│     └── 响应后置处理                                          │
│         - 修改响应                                            │
│         - 添加头部                                            │
│         - 记录日志                                            │
│                                                              │
└─────────────────────────────────────────────────────────────┘

中间件接口 #

Service trait #

rust
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
use actix_web::Error;
use futures::future::{ok, LocalBoxFuture, Ready};

pub struct MyMiddleware;

impl<S, B> Transform<S, ServiceRequest> for MyMiddleware
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = MyMiddlewareService<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(MyMiddlewareService { service })
    }
}

pub struct MyMiddlewareService<S> {
    service: S,
}

impl<S, B> Service<ServiceRequest> for MyMiddlewareService<S>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    fn poll_ready(&self, ctx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
        self.service.poll_ready(ctx)
    }

    fn call(&self, req: ServiceRequest) -> Self::Future {
        println!("Request: {}", req.path());
        
        let fut = self.service.call(req);
        
        Box::pin(async move {
            let mut res = fut.await?;
            println!("Response: {}", res.status());
            Ok(res)
        })
    }
}

中间件应用场景 #

1. 日志记录 #

rust
App::new()
    .wrap(middleware::Logger::default())

2. 认证授权 #

rust
App::new()
    .wrap(AuthMiddleware::new())

3. 错误处理 #

rust
App::new()
    .wrap(middleware::ErrorHandlers::new()
        .handler(http::StatusCode::NOT_FOUND, not_found_handler)
        .handler(http::StatusCode::INTERNAL_SERVER_ERROR, error_handler)
    )

4. CORS 处理 #

rust
use actix_cors::Cors;

App::new()
    .wrap(Cors::permissive())

5. 响应压缩 #

rust
App::new()
    .wrap(middleware::Compress::default())

中间件与守卫对比 #

特性 中间件 守卫
执行时机 路由匹配后 路由匹配前
可修改请求
可修改响应
可中断请求
返回值 Response bool
主要用途 请求/响应处理 请求过滤

下一步 #

现在你已经了解了中间件概念,继续学习 内置中间件,深入了解 Actix Web 提供的内置中间件!

最后更新:2026-03-29