分享免费的编程资源和教程

网站首页 > 技术教程 正文

使用 Rust Actix 快速开发高性能的Web应用

goqiw 2024-10-17 12:04:58 技术教程 78 ℃ 0 评论

Actix 是一个功能强大且高性能的 Rust Web 框架。本章我们将集中探讨如何在 Actix 中编写 Web 应用,并通过实例代码详细阐述各个部分的实现。

写一个简单的应用

actix-web 提供了多种原语来构建 Web 服务器和应用。它包括路由、中间件、请求前处理、响应后处理等功能。所有 actix-web 服务器都围绕 App 实例构建。App 用于注册资源路由和中间件,并存储在相同作用域内所有处理程序之间共享的应用状态。

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

async fn index() -> impl Responder {
    "Hello world!"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new().service(
            // 在这里为所有资源和路由设置前缀 "/app"
            web::scope("/app")
                .route("/index.html", web::get().to(index)),
        )
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

在这个示例中,我们创建了一个带有前缀 /app 和资源 index.html 的应用,通过 /app/index.html URL 访问该资源。

应用状态

可以通过 web::Data<T> 提取器来访问应用状态,其中 T 代表状态数据的类型。让我们编写一个简单的应用并在状态中存储应用程序名称:

use actix_web::{get, web, App, HttpServer};

// 这个结构体代表应用状态
struct AppState {
    app_name: String,
}

#[get("/")]
async fn index(data: web::Data<AppState>) -> String {
    let app_name = &data.app_name; // 获取 app_name
    format!("Hello {app_name}!")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .app_data(web::Data::new(AppState {
                app_name: String::from("Actix Web"),
            }))
            .service(index)
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

可以在应用中注册任意数量的状态类型。

共享可变状态

HttpServer 接受一个应用工厂而不是一个应用实例。HttpServer 为每个线程构建一个应用实例。因此,应用数据必须被多次构建。如果你想在不同线程之间共享数据,应使用可共享对象,例如 Send + Sync

在内部,web::Data 使用 Arc。为了避免创建两个 Arc,我们应在使用 App::app_data() 注册之前创建我们的 Data

use actix_web::{web, App, HttpServer};
use std::sync::Mutex;

struct AppStateWithCounter {
    counter: Mutex<i32>,
}

async fn index(data: web::Data<AppStateWithCounter>) -> String {
    let mut counter = data.counter.lock().unwrap();
    *counter += 1;
    format!("Request number: {counter}")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let counter = web::Data::new(AppStateWithCounter {
        counter: Mutex::new(0),
    });

    HttpServer::new(move || {
        App::new()
            .app_data(counter.clone())
            .route("/", web::get().to(index))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

在这个示例中,我们定义了一种带有计数器的状态,并在处理程序中对其进行处理。需要注意的是,计数器状态的创建和注册是在 HttpServer::new 闭包外部完成的。

使用应用作用域来组合应用

web::scope() 方法允许设置资源组前缀。这个作用域代表一个资源前缀,将会被添加到所有资源模式中。这可以用来帮助在不同位置挂载一组路由,而保持相同资源名称。

#[actix_web::main]
async fn main() {
    let scope = web::scope("/users").service(show_users);
    App::new().service(scope);
}

在这个示例中,show_users 路由的模式将被改为 /users/show 而不是 /show,因为 App 的作用域前缀会添加到模式中。

应用守卫和虚拟主机

你可以将守卫视为一个简单的函数,该函数接受 request 对象引用并返回 truefalse。形式上,守卫是任何实现 Guard 特征的对象。Actix Web 提供了多个守卫。

其中一个守卫是 Host,它可以基于请求头信息作为过滤器。

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(
                web::scope("/")
                    .guard(guard::Host("www.example.com"))
                    .route("", web::to(|| async { HttpResponse::Ok().body("www") })),
            )
            .service(
                web::scope("/")
                    .guard(guard::Host("users.example.com"))
                    .route("", web::to(|| async { HttpResponse::Ok().body("user") })),
            )
            .route("/", web::to(HttpResponse::Ok))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

进行配置

为了简化和重用,Appweb::Scope 提供了 configure 方法。这个函数在将配置部分移动到不同模块或库时非常有用。

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

// 这个函数可以位于不同的模块中
fn scoped_config(cfg: &mut web::ServiceConfig) {
    cfg.service(
        web::resource("/test")
            .route(web::get().to(|| async { HttpResponse::Ok().body("test") }))
            .route(web::head().to(HttpResponse::MethodNotAllowed)),
    );
}

// 这个函数可以位于不同的模块中
fn config(cfg: &mut web::ServiceConfig) {
    cfg.service(
        web::resource("/app")
            .route(web::get().to(|| async { HttpResponse::Ok().body("app") }))
            .route(web::head().to(HttpResponse::MethodNotAllowed)),
    );
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .configure(config)
            .service(web::scope("/api").configure(scoped_config))
            .route(
                "/",
                web::get().to(|| async { HttpResponse::Ok().body("/") }),
            )
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

这个示例的结果是:

  • / -> /
  • /app -> app
  • /api/test -> test

每个 ServiceConfig 都可以有自己的 dataroutesservices

通过这些详尽的示例和详细的解释,相信你已经对如何在 Actix 中编写一个 Web 应用有了深入的了解。Actix 提供的各种功能和特性,使得开发和管理 Web 应用变得更加高效和简单。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表