路由基础 #

什么是路由? #

路由是将 HTTP 请求映射到处理函数的机制。当客户端发送请求时,Actix Web 根据请求的 URL 路径和 HTTP 方法找到对应的处理函数。

text
┌─────────────────────────────────────────────────────────────┐
│                      路由匹配流程                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  HTTP 请求                                                    │
│  GET /users/123                                              │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                   路由表                              │   │
│  │  GET /           → index()                           │   │
│  │  GET /users/{id} → get_user()  ✓ 匹配                │   │
│  │  POST /users     → create_user()                     │   │
│  └─────────────────────────────────────────────────────┘   │
│         │                                                    │
│         ▼                                                    │
│  执行 get_user() 处理函数                                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

基本路由 #

使用 route 方法 #

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

async fn index() -> impl Responder {
    HttpResponse::Ok().body("Welcome!")
}

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

使用属性宏 #

rust
use actix_web::{HttpResponse, Responder};

#[actix_web::get("/")]
async fn index() -> impl Responder {
    HttpResponse::Ok().body("Welcome!")
}

#[actix_web::post("/users")]
async fn create_user() -> impl Responder {
    HttpResponse::Created().body("User created")
}

HTTP 方法 #

Actix Web 支持所有标准 HTTP 方法:

GET 请求 #

rust
#[actix_web::get("/users")]
async fn list_users() -> impl Responder {
    HttpResponse::Ok().json(vec!["Alice", "Bob"])
}

#[actix_web::get("/users/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {
    HttpResponse::Ok().body(format!("User ID: {}", path.into_inner()))
}

POST 请求 #

rust
#[actix_web::post("/users")]
async fn create_user(body: web::Json<CreateUser>) -> impl Responder {
    HttpResponse::Created().json(body.into_inner())
}

PUT 请求 #

rust
#[actix_web::put("/users/{id}")]
async fn update_user(
    path: web::Path<u32>,
    body: web::Json<UpdateUser>,
) -> impl Responder {
    HttpResponse::Ok().json(serde_json::json!({
        "id": path.into_inner(),
        "updated": true
    }))
}

DELETE 请求 #

rust
#[actix_web::delete("/users/{id}")]
async fn delete_user(path: web::Path<u32>) -> impl Responder {
    HttpResponse::NoContent().finish()
}

PATCH 请求 #

rust
#[actix_web::patch("/users/{id}")]
async fn patch_user(
    path: web::Path<u32>,
    body: web::Json<PatchUser>,
) -> impl Responder {
    HttpResponse::Ok().json(serde_json::json!({
        "id": path.into_inner(),
        "patched": true
    }))
}

其他方法 #

rust
#[actix_web::head("/users/{id}")]
async fn head_user(path: web::Path<u32>) -> impl Responder {
    HttpResponse::Ok()
        .insert_header(("X-User-Id", path.into_inner()))
        .finish()
}

#[actix_web::options("/users")]
async fn options_users() -> impl Responder {
    HttpResponse::Ok()
        .insert_header(("Allow", "GET, POST, PUT, DELETE"))
        .finish()
}

路由方法汇总 #

方法 说明
GET #[get("/path")] 获取资源
POST #[post("/path")] 创建资源
PUT #[put("/path")] 完整更新资源
PATCH #[patch("/path")] 部分更新资源
DELETE #[delete("/path")] 删除资源
HEAD #[head("/path")] 获取响应头
OPTIONS #[options("/path")] 获取支持的方法

多方法路由 #

使用 route 配置多个方法 #

rust
App::new()
    .route("/users", web::get().to(list_users))
    .route("/users", web::post().to(create_user))
    .route("/users/{id}", web::get().to(get_user))
    .route("/users/{id}", web::put().to(update_user))
    .route("/users/{id}", web::delete().to(delete_user))

使用 to 方法链 #

rust
App::new()
    .route(
        "/items",
        web::get()
            .guard(guard::Get())
            .to(list_items)
    )
    .route(
        "/items",
        web::post()
            .guard(guard::Post())
            .to(create_item)
    )

路由配置函数 #

使用 configure 模式 #

rust
use actix_web::{web, App, HttpResponse, Responder};

async fn index() -> impl Responder {
    HttpResponse::Ok().body("Index")
}

async fn users() -> impl Responder {
    HttpResponse::Ok().body("Users")
}

fn user_routes(cfg: &mut web::ServiceConfig) {
    cfg.service(
        web::scope("/users")
            .route("", web::get().to(users))
            .route("/{id}", web::get().to(get_user))
    );
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(index))
            .configure(user_routes)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

模块化路由配置 #

rust
mod api {
    use actix_web::{web, HttpResponse, Responder};

    pub fn config(cfg: &mut web::ServiceConfig) {
        cfg.service(
            web::scope("/api")
                .configure(v1::config)
                .configure(v2::config)
        );
    }

    mod v1 {
        use super::*;

        pub fn config(cfg: &mut web::ServiceConfig) {
            cfg.service(
                web::scope("/v1")
                    .route("/users", web::get().to(list_users))
            );
        }

        async fn list_users() -> impl Responder {
            HttpResponse::Ok().json(vec!["v1 users"])
        }
    }

    mod v2 {
        use super::*;

        pub fn config(cfg: &mut web::ServiceConfig) {
            cfg.service(
                web::scope("/v2")
                    .route("/users", web::get().to(list_users))
            );
        }

        async fn list_users() -> impl Responder {
            HttpResponse::Ok().json(vec!["v2 users"])
        }
    }
}

路由匹配规则 #

精确匹配 #

rust
App::new()
    .route("/users", web::get().to(users))  // 只匹配 /users

尾部斜杠处理 #

rust
App::new()
    .route("/users", web::get().to(users))     // 匹配 /users
    .route("/users/", web::get().to(users))    // 匹配 /users/

通配符匹配 #

rust
use actix_web::guard;

App::new()
    .route("/api/{path:.*}", web::get().to(api_handler))  // 匹配 /api/ 下的所有路径

路由优先级 #

路由按注册顺序匹配,先注册的优先:

rust
App::new()
    .route("/users/special", web::get().to(special_users))  // 优先匹配
    .route("/users/{id}", web::get().to(get_user))          // 后匹配

默认路由 #

默认处理函数 #

rust
App::new()
    .route("/", web::get().to(index))
    .default_service(web::to(not_found))

async fn not_found() -> impl Responder {
    HttpResponse::NotFound().body("Page not found")
}

404 处理 #

rust
App::new()
    .route("/", web::get().to(index))
    .default_service(
        web::route()
            .guard(guard::Not(guard::Get()))
            .to(HttpResponse::MethodNotAllowed)
    )
    .default_service(
        web::route()
            .guard(guard::Get())
            .to(not_found)
    )

路由资源 #

使用 resource #

rust
App::new()
    .service(
        web::resource("/users")
            .route(web::get().to(list_users))
            .route(web::post().to(create_user))
    )
    .service(
        web::resource("/users/{id}")
            .route(web::get().to(get_user))
            .route(web::put().to(update_user))
            .route(web::delete().to(delete_user))
    )

资源名称 #

rust
App::new()
    .service(
        web::resource("/users/{id}")
            .name("user_detail")
            .route(web::get().to(get_user))
    )

路由守卫 #

基本守卫 #

rust
use actix_web::guard;

App::new()
    .route(
        "/api",
        web::route()
            .guard(guard::Get())
            .guard(guard::Header("content-type", "application/json"))
            .to(api_handler)
    )

自定义守卫 #

rust
use actix_web::{guard::Guard, guard::GuardContext, http::header};

struct ContentTypeJson;

impl Guard for ContentTypeJson {
    fn check(&self, req: &GuardContext) -> bool {
        req.head()
            .headers()
            .get(header::CONTENT_TYPE)
            .map(|v| v == "application/json")
            .unwrap_or(false)
    }
}

App::new()
    .route(
        "/api",
        web::route()
            .guard(ContentTypeJson)
            .to(api_handler)
    )

路由组 #

使用 scope #

rust
App::new()
    .service(
        web::scope("/api/v1")
            .route("/users", web::get().to(list_users))
            .route("/posts", web::get().to(list_posts))
    )

嵌套 scope #

rust
App::new()
    .service(
        web::scope("/api")
            .service(
                web::scope("/v1")
                    .route("/users", web::get().to(list_users))
            )
            .service(
                web::scope("/v2")
                    .route("/users", web::get().to(list_users_v2))
            )
    )

完整示例 #

rust
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct User {
    id: u32,
    name: String,
}

#[actix_web::get("/")]
async fn index() -> impl Responder {
    HttpResponse::Ok().body("Welcome to Actix Web!")
}

#[actix_web::get("/users")]
async fn list_users() -> impl Responder {
    HttpResponse::Ok().json(vec![
        User { id: 1, name: "Alice".to_string() },
        User { id: 2, name: "Bob".to_string() },
    ])
}

#[actix_web::get("/users/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {
    let id = path.into_inner();
    HttpResponse::Ok().json(User {
        id,
        name: format!("User {}", id),
    })
}

#[actix_web::post("/users")]
async fn create_user(user: web::Json<User>) -> impl Responder {
    HttpResponse::Created().json(user.into_inner())
}

#[actix_web::put("/users/{id}")]
async fn update_user(path: web::Path<u32>, user: web::Json<User>) -> impl Responder {
    let id = path.into_inner();
    HttpResponse::Ok().json(User {
        id,
        name: user.name.clone(),
    })
}

#[actix_web::delete("/users/{id}")]
async fn delete_user(path: web::Path<u32>) -> impl Responder {
    let id = path.into_inner();
    HttpResponse::Ok().json(serde_json::json!({
        "deleted": id
    }))
}

fn api_config(cfg: &mut web::ServiceConfig) {
    cfg.service(
        web::scope("/api")
            .service(list_users)
            .service(get_user)
            .service(create_user)
            .service(update_user)
            .service(delete_user)
    );
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(index)
            .configure(api_config)
            .default_service(web::to(not_found))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

async fn not_found() -> impl Responder {
    HttpResponse::NotFound().json(serde_json::json!({
        "error": "Not found"
    }))
}

下一步 #

现在你已经掌握了路由基础,继续学习 路由属性,深入了解属性宏的使用!

最后更新:2026-03-29