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
語
言
」
學
習
資
料