actix-web 中文文档

actix-web 是 Rust 生态中的最为优秀的 web 框架之一,具有类型安全、功能丰富、扩展性强,以及速度极快的诸多优点。

总览

让我们通过 actix-web 的典型代码,来对其做一个整体认知。

use actix_web::{web, App, HttpRequest, HttpServer, Responder};

async fn greet(req: HttpRequest) -> impl Responder {
    let name = req.match_info().get("name").unwrap_or("World");
    format!("Hello {}!", &name)
}

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

类型安全

忘掉字符串类型的对象吧,从请求到响应,所有的数据信息都有类型。

功能丰富

actix 提供了诸多开箱即用的功能和特性,如 HTTP/2、日志记录等。

扩展性强

轻松创建自定义库,任何 actix 应用程序都可以无缝集成。

速度极快

Actix 具有极快的速度,请参见 techempower 性能基准测试

实践

灵活响应

actix 中的处理函数可以返回大量实现了 Responder trait 的对象,这使得从诸多 API 返回一致的响应变得轻而易举。

#![allow(unused)]
fn main() {
#[derive(Serialize)]
struct Measurement {
    temperature: f32,
}

async fn hello_world() -> impl Responder {
    "Hello World!"
}

async fn current_temperature() -> impl Responder {
    web::Json(Measurement { temperature: 42.3 })
}
}

增强萃取

actix 自实现了一个强大的提取器系统,可以从传入的 HTTP 请求中提取数据,并将其传递给视图函数。这不仅有助于实现一个简捷的 API,而且还意味着你的视图函数可以是同步代码,但仍然受益于异步 IO 处理。

#![allow(unused)]
fn main() {
#[derive(Deserialize, Serialize)]
struct Event {
    id: Option<i32>,
    timestamp: f64,
    kind: String,
    tags: Vec<String>,
}

async fn capture_event(evt: web::Json<Event>) -> impl Responder {
    let new_event = store_in_db(evt.timestamp, &evt.kind, &evt.tags);
    format!("got event {}", new_event.id.unwrap())
}
}

简便的表单处理

处理 multipart/urlencoded 表单数据很容易。只需定义一个可以反序列化的结构,actix 将处理其余部分。

#![allow(unused)]
fn main() {
#[derive(Deserialize)]
struct Register {
    username: String,
    country: String,
}

async fn register(form: web::Form<Register>) -> impl Responder {
    format!("Hello {} from {}!", form.username, form.country)
}
}

具备请求路由

actix 具备 URL 路由系统,可以匹配 URL 并调用各个 handler。为了获得额外的灵活性,可以使用作用域。

#![allow(unused)]
fn main() {
#[get("/")]
async fn index(_req: HttpRequest) -> impl Responder {
    "Hello from the index page!"
}

async fn hello(path: web::Path<String>) -> impl Responder {
    format!("Hello {}!", &path)
}

let app = App::new()
    .service(index)
    .route("/{name}", web::get().to(hello));
}