路由基础 #
什么是路由? #
路由是将 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