當前位置: 妍妍網 > 碼農

使用 Rust Actix 快速開發高效能的Web套用

2024-05-30碼農

Actix 是一個功能強大且高效能的 Rust Web 框架。本章我們將集中探討如何在 Actix 中編寫 Web 套用,並透過例項程式碼詳細闡述各個部份的實作。

寫一個簡單的套用

actix-web 提供了多種原語來構建 Web 伺服器和套用。它包括路由、中介軟體、請求前處理、響應後處理等功能。所有 actix-web 伺服器都圍繞 App 例項構建。 App 用於註冊資源路由和中介軟體,並儲存在相同作用域內所有處理常式之間共享的套用狀態。

use actix_web::{web, App, HttpServer, Responder};
asyncfnindex() -> impl Responder {
"Hello world!"
}
#[actix_web::main]
asyncfnmain() -> 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};
// 這個結構體代表套用狀態
structAppState {
app_name: String,
}
#[get("/")]
asyncfnindex(data: web::Data<AppState>) -> String {
let app_name = &data.app_name; // 獲取 app_name
format!("Hello {app_name}!")
}
#[actix_web::main]
asyncfnmain() -> 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;
structAppStateWithCounter {
counter: Mutex<i32>,
}
asyncfnindex(data: web::Data<AppStateWithCounter>) -> String {
letmut counter = data.counter.lock().unwrap();
*counter += 1;
format!("Request number: {counter}")
}
#[actix_web::main]
asyncfnmain() -> 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]
asyncfnmain() {
let scope = web::scope("/users").service(show_users);
App::new().service(scope);
}

在這個範例中, show_users 路由的模式將被改為 /users/show 而不是 /show ,因為 App 的作用域字首會添加到模式中。

套用守衛和虛擬主機

你可以將守衛視為一個簡單的函式,該函式接受 request 物件參照並返回 true false 。形式上,守衛是任何實作 Guard 特征的物件。Actix Web 提供了多個守衛。

其中一個守衛是 Host ,它可以基於請求頭資訊作為過濾器。

#[actix_web::main]
asyncfnmain() -> 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
}

進行配置

為了簡化和重用, App web::Scope 提供了 configure 方法。這個函式在將配置部份移動到不同模組或庫時非常有用。

use actix_web::{web, App, HttpResponse, HttpServer};
// 這個函式可以位於不同的模組中
fnscoped_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)),
);
}
// 這個函式可以位於不同的模組中
fnconfig(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]
asyncfnmain() -> 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 都可以有自己的 data routes services

    透過這些詳盡的範例和詳細的解釋,相信你已經對如何在 Actix 中編寫一個 Web 套用有了深入的了解。Actix 提供的各種功能和特性,使得開發和管理 Web 套用變得更加高效和簡單。

    文章精選

    「Rust