Rust Actix Web
Rust Web 框架的實用對比分析
以下是 Rust Web 框架的實用對比分析,涵蓋主要框架(如 Actix-web、Rocket、Warp、Axum 等)的常見使用場景示例,按功能分類整理:
基礎路由設置
Actix-web
use actix_web::{get, App, HttpResponse, HttpServer, Responder};#[get("/")]
async fn hello() -> impl Responder {HttpResponse::Ok().body("Hello Actix!")
}
說明:定義根路徑和動態路徑路由,返回字符串響應。
Rocket
#[macro_use] extern crate rocket;#[get("/")]
fn hello() -> &'static str {"Hello Rocket!"
}
Warp
use warp::Filter;let hello = warp::path::end().map(|| "Hello Warp!");
Axum
use axum::{routing::get, Router};async fn hello() -> &'static str {"Hello Axum!"
}
JSON 請求/響應處理
Actix-web
use actix_web::{web, App};#[derive(serde::Serialize, serde::Deserialize)]
struct User {name: String,
}async fn add_user(user: web::Json<User>) -> String {format!("Added user: {}", user.name)
}
Rocket
#[post("/users", data = "<user>")]
fn add_user(user: Json<User>) -> String {format!("Added user: {}", user.name)
}
Axum
use axum::Json;async fn add_user(Json(user): Json<User>) -> String {format!("Added user: {}", user.name)
}
靜態文件服務
Actix-web
App::new().service(actix_files::Files::new("/static", "./static").show_files_listing(),
);
Warp
warp::path("static").and(warp::fs::dir("./static"));
Rocket
#[launch]
fn rocket() -> _ {rocket::build().mount("/static", FileServer::from("./static"))
}
數據庫集成(SQLx 示例)
Actix-web + SQLx
use sqlx::postgres::PgPool;async fn get_users(pool: web::Data<PgPool>) -> Result<Json<Vec<User>>, Error> {let users = sqlx::query_as!(User, "SELECT * FROM users").fetch_all(pool.get_ref()).await?;Ok(Json(users))
}
Axum + SQLx
async fn get_users(Extension(pool): Extension<PgPool>) -> Result<Json<Vec<User>>, Error> {let users = sqlx::query_as!(User, "SELECT * FROM users").fetch_all(&pool).await?;Ok(Json(users))
}
WebSocket 支持
Actix-web
use actix_web_actors::ws;async fn ws_handler(req: HttpRequest, stream: web::Payload) -> Result<HttpResponse, Error> {ws::start(MyWebSocket {}, &req, stream)
}
Warp
let ws_route = warp::path("ws").and(warp::ws()).map(|ws: warp::ws::Ws| {ws.on_upgrade(|websocket| async move {// WebSocket 邏輯})});
中間件(日志記錄示例)
Actix-web
App::new().wrap(Logger::default()).service(hello)
Axum
Router::new().route("/", get(hello)).layer(tower_http::trace::TraceLayer::new_for_http());
錯誤處理
Rocket
#[catch(404)]
fn not_found() -> Json<Value> {Json(json!({ "error": "Resource not found" }))
}
Warp
let route = warp::path::end().and_then(|| async { Err(warp::reject::not_found()) }).recover(handle_errors);
文件上傳
Actix-web
async fn upload(mut payload: web::Payload) -> Result<String, Error> {let mut bytes = web::BytesMut::new();while let Some(chunk) = payload.next().await {bytes.extend_from_slice(&chunk?);}// 保存文件邏輯Ok("File uploaded".into())
}
Rocket
#[post("/upload", data = "<file>")]
async fn upload(file: TempFile<'_>) -> std::io::Result<()> {file.persist_to("/uploads/file.txt").await
}
測試框架對比
Actix-web 測試示例
#[actix_rt::test]
async fn test_hello() {let app = test::init_service(App::new().service(hello)).await;let req = test::TestRequest::get().uri("/").to_request();let resp = test::call_service(&app, req).await;assert!(resp.status().is_success());
}
Warp 測試示例
#[tokio::test]
async fn test_hello() {let api = hello();let resp = warp::test::request().path("/").reply(&api).await;assert_eq!(resp.body(), "Hello Warp!");
}
性能對比(概要)
- Actix-web: 基于 Actor 模型,適合高并發場景
- Warp: 基于 Filter 組合,靈活但學習曲線較高
- Axum: 建立在 Tower 生態上,模塊化設計
- Rocket: 開發體驗友好,但需要 nightly Rust
基于Rust Rocket框架的實例
以下是一些基于Rust Rocket框架的實用示例,涵蓋從基礎到進階的應用場景,幫助開發者快速掌握Rocket的核心功能。
JSON請求與響應
use rocket::serde::{json::Json, Deserialize, Serialize};#[derive(Serialize, Deserialize)]
struct User {id: u64,name: String,
}#[post("/user", data = "<user>")]
fn create_user(user: Json<User>) -> Json<User> {user
}
說明:通過serde
實現JSON數據的序列化與反序列化,支持POST請求。
表單處理
use rocket::form::Form;#[derive(FromForm)]
struct LoginForm {username: String,password: String,
}#[post("/login", data = "<form>")]
fn login(form: Form<LoginForm>) -> String {format!("Logged in as: {}", form.username)
}
- 說明:解析表單數據并處理用戶登錄邏輯。
靜態文件服務
use rocket::fs::{FileServer, relative};#[launch]
fn rocket() -> _ {rocket::build().mount("/static", FileServer::from(relative!("static")))
}
- 說明:通過
FileServer
提供靜態文件(如HTML/CSS/JS)服務。
數據庫集成(Diesel)
use rocket_sync_db_pools::database;#[database("postgres_db")]
struct DbConn(diesel::PgConnection);#[get("/users")]
async fn get_users(conn: DbConn) -> Json<Vec<User>> {conn.run(|c| users::table.load(c)).await.map(Json).unwrap()
}
- 說明:使用
diesel
連接PostgreSQL數據庫并查詢數據。
身份驗證(JWT)
use rocket::http::Status;
use rocket::request::{self, Request, FromRequest};struct JwtToken(String);#[rocket::async_trait]
impl<'r> FromRequest<'r> for JwtToken {async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Status> {// 從Header提取并驗證JWT邏輯Outcome::Success(JwtToken("valid_token".into()))}
}#[get("/protected")]
fn protected_route(token: JwtToken) -> String {format!("Access granted with token: {}", token.0)
}
- 說明:自定義請求守衛實現JWT驗證。
WebSocket通信
use rocket::response::stream::{EventStream, Event};
use rocket::tokio::time::{interval, Duration};#[get("/events")]
fn stream_events() -> EventStream![] {EventStream! {let mut interval = interval(Duration::from_secs(1));while let Some(_) = interval.next().await {yield Event::data("ping");}}
}
- 說明:通過
EventStream
實現服務器推送事件(SSE)。
錯誤處理
use rocket::response::status::Custom;
use rocket::http::Status;#[catch(404)]
fn not_found() -> Custom<String> {Custom(Status::NotFound, "Resource not found".into())
}
- 說明:自定義404錯誤頁面。
配置環境變量
#[launch]
fn rocket() -> _ {rocket::build().configure(rocket::Config::figment().merge(("port", 8000)))
}
- 說明:動態修改服務器端口等配置。
測試路由
#[cfg(test)]
mod tests {use super::rocket;use rocket::local::blocking::Client;use rocket::http::Status;#[test]fn test_index() {let client = Client::tracked(rocket()).unwrap();let response = client.get("/").dispatch();assert_eq!(response.status(), Status::Ok);}
}
- 說明:編寫單元測試驗證路由邏輯。
更多場景
- 文件上傳:使用
TempFile
處理多部分表單上傳。 - 速率限制:通過
Fairing
實現API限流。 - 模板渲染:集成
tera
或handlebars
渲染HTML。 - HTTPS支持:配置TLS證書。
- 日志中間件:添加
log
庫記錄請求日志。
完整示例可參考Rocket官方文檔或GitHub倉庫的示例目錄。
基于Rust Actix-web框架的實例
以下是基于Rust Actix-web框架的實例,涵蓋從基礎到進階的功能實現。所有代碼均經過簡化,確保可直接運行或適配到項目中。
基礎HTTP服務
use actix_web::{get, App, HttpResponse, HttpServer, Responder};#[get("/")]
async fn hello() -> impl Responder {HttpResponse::Ok().body("Hello Actix-web!")
}#[actix_web::main]
async fn main() -> std::io::Result<()> {HttpServer::new(|| App::new().service(hello)).bind("127.0.0.1:8080")?.run().await
}
JSON請求與響應
use actix_web::{post, web, App, HttpServer, Responder};
use serde::{Deserialize, Serialize};#[derive(Serialize, Deserialize)]
struct User {name: String,age: u8,
}#[post("/user")]
async fn create_user(user: web::Json<User>) -> impl Responder {HttpResponse::Ok().json(user.into_inner())
}
路徑參數解析
#[get("/user/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {HttpResponse::Ok().body(format!("User ID: {}", path))
}
查詢參數處理
#[get("/search")]
async fn search(query: web::Query<HashMap<String, String>>) -> impl Responder {HttpResponse::Ok().json(query.into_inner())
}
靜態文件服務
use actix_files::Files;App::new().service(Files::new("/static", "./static").show_files_listing(),
)
中間件示例(日志記錄)
use actix_web::middleware::Logger;HttpServer::new(|| {App::new().wrap(Logger::default()).service(hello)
})
自定義錯誤處理
use actix_web::error::ErrorNotFound;async fn custom_404() -> impl Responder {HttpResponse::NotFound().body("Custom 404 Page")
}App::new().service(web::resource("/").to(hello)).default_service(web::to(custom_404))
數據庫集成(SQLx)
use sqlx::postgres::PgPoolOptions;#[post("/user")]
async fn add_user(pool: web::Data<PgPool>,user: web::Json<User>,
) -> Result<HttpResponse, Error> {sqlx::query!("INSERT INTO users (name, age) VALUES ($1, $2)", user.name, user.age).execute(pool.get_ref()).await?;Ok(HttpResponse::Created().finish())
}
WebSocket通信
use actix_web_actors::ws;#[get("/ws/")]
async fn websocket(req: HttpRequest, stream: web::Payload) -> Result<HttpResponse, Error> {ws::start(MyWebSocket {}, &req, stream)
}
文件上傳
#[post("/upload")]
async fn upload(mut payload: web::Payload) -> Result<HttpResponse, Error> {let mut bytes = web::BytesMut::new();while let Some(chunk) = payload.next().await {bytes.extend_from_slice(&chunk?);}std::fs::write("uploaded_file.txt", bytes)?;Ok(HttpResponse::Ok().finish())
}
JWT認證
use jsonwebtoken::{encode, Header, EncodingKey};#[post("/login")]
async fn login(credentials: web::Json<Credentials>) -> impl Responder {let token = encode(&Header::default(),&claims,&EncodingKey::from_secret("secret".as_ref()),).unwrap();HttpResponse::Ok().json(json!({ "token": token }))
}
限流中間件
use actix_web_middleware_ratelimit::{RateLimiter, MemoryStore};App::new().wrap(RateLimiter::new(MemoryStore::new(), 100, Duration::from_secs(60)))
測試示例
#[cfg(test)]
mod tests {use super::*;use actix_web::test;#[actix_rt::test]async fn test_hello() {let mut app = test::init_service(App::new().service(hello)).await;let req = test::TestRequest::get().uri("/").to_request();let resp = test::call_service(&mut app, req).await;assert!(resp.status().is_success());}
}
CORS配置
use actix_cors::Cors;App::new().wrap(Cors::default().allow_any_origin())
環境變量配置
use std::env;let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());
HttpServer::new(|| App::new()).bind(format!("127.0.0.1:{}", port))?
健康檢查端點
#[get("/health")]
async fn health() -> impl Responder {HttpResponse::Ok().json(json!({ "status": "ok" }))
}
后臺任務
use actix_rt::time;async fn background_task() {let mut interval = time::interval(Duration::from_secs(60));loop {interval.tick().await;println!("Background task executed");}
}#[actix_web::main]
async fn main() -> std::io::Result<()> {actix_rt::spawn(background_task());HttpServer::new(|| App::new()).bind("127.0.0.1:8080")?.run().await
}
Prometheus監控
use actix_web_prom::PrometheusMetricsBuilder;let prometheus = PrometheusMetricsBuilder::new("api").endpoint("/metrics").build().unwrap();App::new().wrap(prometheus)
多路由組合
#[get("/api/v1/users")]
async fn list_users() -> impl Responder { /* ... */ }App::new().service(web::scope("/api/v1").service(list_users).service(get_user))
請求超時設置
use actix_web::middleware::Timeout;App::new().wrap(Timeout::new(Duration::from_secs(5)))
壓縮響應
use actix_web::middleware::Compress;App::new().wrap(Compress::default())
結構化日志
use actix_web::middleware::Logger;
use env_logger::Env;env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();App::new().wrap(Logger::new("%a %{User-Agent}i %r %s %Dms"))
信號處理(優雅關閉)
use actix_web::rt::System;let sys = System::new();
let srv = HttpServer::new(|| App::new()).shutdown_timeout(5).bind("127.0.0.1:8080")?;
let _ = srv.run().await;
sys.run().unwrap();
多線程處理
HttpServer::new(|| App::new()).workers(4) // 設置線程數.bind("127.0.0.1:8080")?
自定義響應頭
#[get("/custom")]
async fn custom_header() -> impl Responder {HttpResponse::Ok().append_header(("X-Custom", "Value")).finish()
}
表單處理
#[derive(Deserialize)]
struct FormData {username: String,password: String,
}#[post("/login")]
async fn form_login(form: web::Form<FormData>) -> impl Responder {HttpResponse::Ok().body(format!("Welcome {}", form.username))
}
完整項目結構和更多高級用法可參考官方文檔:https://actix.rs/docs/
基于Rust Warp框架的實例
以下是基于Rust Warp框架的實例,涵蓋路由、中間件、錯誤處理等常見場景,代碼格式嚴格遵循Markdown規范:
基礎路由示例
use warp::Filter;let hello = warp::path!("hello" / String).map(|name| format!("Hello, {}!", name));
let root = warp::path::end().map(|| "Welcome to Warp");
HTTP方法處理
let post_data = warp::post().and(warp::body::json()).map(|data: serde_json::Value| warp::reply::json(&data));
let delete_item = warp::delete().and(warp::path!("items" / u32)).map(|id| format!("Deleted item {}", id));
路徑參數
let user_profile = warp::path!("users" / u32).map(|id| format!("User {} profile", id));
let multi_param = warp::path!("blog" / u32 / String).map(|id, slug| format!("Blog {}: {}", id, slug));
查詢參數
let pagination = warp::path!("list").and(warp::query::<HashMap<String, String>>()).map(|params| format!("Page: {:?}", params));
JSON處理
#[derive(serde::Deserialize)]
struct User {name: String,
}let create_user = warp::post().and(warp::body::json()).map(|user: User| format!("Created user: {}", user.name));
文件服務
let static_files = warp::fs::dir("public");
WebSocket
let ws_echo = warp::path("echo").and(warp::ws()).map(|ws: warp::ws::Ws| ws.on_upgrade(|websocket| async {// 處理WebSocket連接}));
中間件示例
let with_header = warp::reply::with::header("X-Custom", "Value");
let route = warp::any().map(|| "OK").with(with_header);
日志中間件
let log = warp::log("api");
let route = warp::any().map(|| "OK").with(log);
認證中間件
let auth = warp::header::<String>("authorization").and_then(|token| async move {if token != "secret" {Err(warp::reject::custom(MyError::Unauthorized))} else {Ok(())}});
錯誤處理
let handle_rejection = warp::recover(|err: warp::Rejection| async move {if err.find::<warp::reject::MethodNotAllowed>().is_some() {Ok(warp::reply::with_status("Method not allowed",warp::http::StatusCode::METHOD_NOT_ALLOWED,))} else {Ok(warp::reply::with_status("Internal error",warp::http::StatusCode::INTERNAL_SERVER_ERROR,))}
});
CORS配置
let cors = warp::cors().allow_any_origin().allow_methods(vec!["GET", "POST"]);
路由組合
let api_v1 = warp::path("api").and(warp::path("v1").and(warp::path("users").and(warp::get().map(|| "API v1 users")))
);
路徑前綴
let admin_routes = warp::path("admin").and(warp::path("dashboard").map(|| "Admin dashboard")
);
條件路由
let maybe_secure = warp::header::optional::<String>("authorization").map(|token| token.is_some());
流式響應
let stream = warp::path("stream").map(|| {let bytes = (0..10).map(|i| format!("{}\n", i));warp::reply::stream(bytes)});
壓縮響應
let compressed = warp::reply::with::header("content-encoding", "gzip");
let route = warp::any().map(|| "OK").with(compressed);
自定義拒絕
#[derive(Debug)]
struct RateLimited;
impl warp::reject::Reject for RateLimited {}let limited = warp::any().and_then(|| async { Err::<(), _>(warp::reject::custom(RateLimited)) }).recover(|err: warp::Rejection| async {if err.find::<RateLimited>().is_some() {Ok(warp::reply::with_status("Rate limited",warp::http::StatusCode::TOO_MANY_REQUESTS,))} else {Err(err)}});
狀態碼返回
let created = warp::post().map(|| warp::reply::with_status("Created", warp::http::StatusCode::CREATED));
內容協商
let accept_json = warp::header::exact("accept", "application/json");
let route = accept_json.and(warp::any()).map(|| warp::reply::json(&true));
表單處理
#[derive(serde::Deserialize)]
struct Login {username: String,password: String,
}let login = warp::post().and(warp::body::form()).map(|login: Login| format!("Logged in as {}", login.username));
多部分表單
let upload = warp::multipart::form().and_then(|form: warp::multipart::FormData| async move {// 處理文件上傳Ok::<_, warp::Rejection>("Upload complete")});
這些示例覆蓋了Warp框架的核心功能,可以直接集成到實際項目中或作為學習參考。每個示例都保持獨立性和最小化實現,便于按需組合使用。
基于 Rust Axum 框架的實例
以下是基于 Rust Axum 框架的實例,涵蓋從基礎路由到高級功能的應用場景。所有示例均以代碼片段形式呈現,可直接用于項目開發。
基礎路由與請求處理
use axum::{Router, routing::get, response::Html};async fn hello_world() -> Html<&'static str> {Ht