基于 Rust 的Actix Web 框架的應用與優化實例
Actix Web 框架概述
Actix Web 是一個基于 Rust 的高性能、輕量級 Web 框架,構建于 Actix 異步運行時之上。它支持異步編程模型,適合構建高并發、低延遲的 Web 服務和 API。
核心特性
- 異步支持:基于
async/await
語法,充分利用 Rust 的異步生態。 - 高性能:底層使用 actor 模型和零成本抽象,性能接近原生代碼。
- 類型安全:通過 Rust 的類型系統確保路由、請求和響應的安全性。
- 靈活的路由:支持 RESTful 路由、動態路徑參數和中間件。
- WebSocket 支持:內置 WebSocket 協議支持。
基本項目結構
典型的 Actix Web 項目結構如下:
src/
├── main.rs # 應用入口和路由配置
├── handlers.rs # 請求處理邏輯
├── models.rs # 數據模型
└── lib.rs # 模塊定義(可選)
快速入門示例
以下是一個最小化的 Actix Web 應用代碼:
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
}
關鍵組件
-
路由與處理函數
- 使用
#[get]
、#[post]
等宏定義路由。 - 處理函數返回
impl Responder
,支持多種響應類型(如HttpResponse
、String
)。
- 使用
-
狀態共享
通過Data<T>
類型共享全局狀態(如數據庫連接池):App::new().app_data(Data::new(AppState { db: pool }))
-
中間件
使用wrap
添加中間件(如日志、認證):App::new().wrap(Logger::default())
-
錯誤處理
自定義錯誤類型并實現ResponseError
trait:impl ResponseError for MyError {fn error_response(&self) -> HttpResponse {HttpResponse::InternalServerError().finish()} }
安裝 Actix Web 依賴 在 Cargo.toml
中添加以下依賴:
[dependencies]
actix-web = "4"
創建基礎 HTTP 服務器
use actix_web::{get, App, HttpResponse, HttpServer, Responder};#[get("/")]
async fn hello() -> impl Responder {HttpResponse::Ok().body("Hello world!")
}#[actix_web::main]
async fn main() -> std::io::Result<()> {HttpServer::new(|| App::new().service(hello)).bind(("127.0.0.1", 8080))?.run().await
}
路由處理示例
多路由配置
use actix_web::{web, App, HttpResponse, HttpServer};async fn index() -> HttpResponse {HttpResponse::Ok().body("Index page")
}async fn about() -> HttpResponse {HttpResponse::Ok().body("About page")
}#[actix_web::main]
async fn main() -> std::io::Result<()> {HttpServer::new(|| {App::new().route("/", web::get().to(index)).route("/about", web::get().to(about))}).bind(("127.0.0.1", 8080))?.run().await
}
路徑參數提取
use actix_web::{get, web, App, HttpServer};#[get("/users/{user_id}/{friend}")]
async fn user_info(path: web::Path<(u32, String)>) -> String {let (user_id, friend) = path.into_inner();format!("User {}'s friend: {}", user_id, friend)
}
以下是基于Rust的路由處理示例,涵蓋不同框架和場景的實用案例。示例分為基礎路由、動態參數、中間件、錯誤處理等類別,代碼均以實際可運行為目標。
基礎路由(axum框架)
use axum::{Router, routing::get, Json};
use serde_json::json;async fn hello_world() -> Json<serde_json::Value> {Json(json!({ "message": "Hello, world!" }))
}#[tokio::main]
async fn main() {let app = Router::new().route("/", get(hello_world));axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
}
動態路徑參數
use axum::{Router, routing::get, extract::Path};async fn user_info(Path(user_id): Path<u32>) -> String {format!("User ID: {}", user_id)
}let app = Router::new().route("/users/:user_id", get(user_info));
查詢參數處理
use axum::{Router, routing::get, extract::Query};
use serde::Deserialize;#[derive(Deserialize)]
struct Pagination {page: usize,per_page: usize,
}async fn list_items(Query(pagination): Query<Pagination>) -> String {format!("Page: {}, Per Page: {}", pagination.page, pagination.per_page)
}let app = Router::new().route("/items", get(list_items));
JSON請求體處理
use axum::{Router, routing::post, Json, extract::Extension};
use serde::{Deserialize, Serialize};#[derive(Deserialize)]
struct CreateUser {name: String,
}#[derive(Serialize)]
struct User {id: u64,name: String,
}async fn create_user(Json(input): Json<CreateUser>) -> Json<User> {Json(User { id: 1, name: input.name })
}let app = Router::new().route("/users", post(create_user));
中間件示例(日志記錄)
use axum::{Router, routing::get, middleware};
use tower_http::trace::TraceLayer;async fn handler() -> &'static str { "OK" }let app = Router::new().route("/", get(handler)).layer(TraceLayer::new_for_http());
錯誤處理
use axum::{Router, routing::get, response::IntoResponse, http::StatusCode};async fn fallible_handler() -> Result<String, (StatusCode, &'static str)> {Err((StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong"))
}let app = Router::new().route("/error", get(fallible_handler));
靜態文件服務
use axum::{Router, routing::get_service};
use tower_http::services::ServeDir;let app = Router::new().nest_service("/static",get_service(ServeDir::new("./static"))
);
路由嵌套
use axum::{Router, routing::get};async fn api_v1_users() -> &'static str { "v1 users" }
async fn api_v2_users() -> &'static str { "v2 users" }let api_v1 = Router::new().route("/users", get(api_v1_users));
let api_v2 = Router::new().route("/users", get(api_v2_users));
let app = Router::new().nest("/api/v1", api_v1).nest("/api/v2", api_v2);
異步數據庫操作
use axum::{Router, routing::get, Extension};
use sqlx::postgres::PgPoolOptions;async fn db_handler(Extension(pool): Extension<sqlx::PgPool>) -> String {let row: (i64,) = sqlx::query_as("SELECT $1").bind(150_i64).fetch_one(&pool).await.unwrap();format!("Result: {}", row.0)
}#[tokio::main]
async fn main() {let pool = PgPoolOptions::new().connect("postgres://user:pass@localhost/db").await.unwrap();let app = Router::new().route("/db", get(db_handler)).layer(Extension(pool));
}
WebSocket路由(axum)
use axum::{Router, routing::get, extract::ws::WebSocketUpgrade};async fn ws_handler(ws: WebSocketUpgrade) -> impl IntoResponse {ws.on_upgrade(|socket| async move {// WebSocket處理邏輯})
}let app = Router::new().route("/ws", get(ws_handler));
JSON 請求與響應
JSON 響應處理
use actix_web::{get, App, HttpServer, Responder};
use serde::Serialize;#[derive(Serialize)]
struct MyObj {name: String,age: u8,
}#[get("/json")]
async fn json_response() -> impl Responder {web::Json(MyObj {name: "Alice".to_string(),age: 30,})
}
JSON 請求處理
use actix_web::{post, web, App, HttpServer, Responder};
use serde::Deserialize;#[derive(Deserialize)]
struct Info {username: String,
}#[post("/submit")]
async fn submit(info: web::Json<Info>) -> impl Responder {format!("Welcome {}!", info.username)
}
以下是基于Rust的JSON請求與響應處理的實用示例集合,涵蓋常見場景和庫(如serde
、reqwest
、actix-web
等)。示例按功能分類,每個示例獨立可用。
基礎序列化與反序列化
use serde::{Deserialize, Serialize};#[derive(Debug, Serialize, Deserialize)]
struct User {id: u32,name: String,
}// 序列化結構體到JSON字符串
let user = User { id: 1, name: "Alice".to_string() };
let json_str = serde_json::to_string(&user).unwrap();
println!("Serialized: {}", json_str); // {"id":1,"name":"Alice"}// 反序列化JSON字符串到結構體
let decoded_user: User = serde_json::from_str(&json_str).unwrap();
println!("Deserialized: {:?}", decoded_user);
使用reqwest發送GET請求
use reqwest::Error;#[tokio::main]
async fn main() -> Result<(), Error> {let response = reqwest::get("https://jsonplaceholder.typicode.com/posts/1").await?.json::<serde_json::Value>().await?;println!("Response: {:?}", response);Ok(())
}
使用reqwest發送POST請求
#[derive(Serialize)]
struct Post {title: String,body: String,userId: u32,
}#[tokio::main]
async fn main() -> Result<(), Error> {let new_post = Post {title: "Test Title".to_string(),body: "Test Body".to_string(),userId: 1,};let client = reqwest::Client::new();let res = client.post("https://jsonplaceholder.typicode.com/posts").json(&new_post).send().await?.json::<serde_json::Value>().await?;println!("Response: {:?}", res);Ok(())
}
使用actix-web處理JSON請求
use actix_web::{web, App, HttpServer, Responder};#[derive(Deserialize)]
struct Info {username: String,
}async fn greet(info: web::Json<Info>) -> impl Responder {format!("Hello {}!", info.username)
}#[actix_web::main]
async fn main() -> std::io::Result<()> {HttpServer::new(|| App::new().route("/greet", web::post().to(greet))).bind("127.0.0.1:8080")?.run().await
}
處理嵌套JSON結構
#[derive(Serialize, Deserialize)]
struct Address {street: String,city: String,
}#[derive(Serialize, Deserialize)]
struct Profile {name: String,age: u8,address: Address,
}let profile = Profile {name: "Bob".to_string(),age: 30,address: Address {street: "Main St".to_string(),city: "Metropolis".to_string(),},
};let json = serde_json::to_string_pretty(&profile).unwrap();
println!("{}", json);
自定義字段名稱
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Product {product_id: u32,product_name: String,
}let product = Product {product_id: 101,product_name: "Laptop".to_string(),
};
let json = serde_json::to_string(&product).unwrap(); // {"productId":101,"productName":"Laptop"}
處理可選字段
#[derive(Serialize, Deserialize)]
struct Book {title: String,#[serde(skip_serializing_if = "Option::is_none")]subtitle: Option<String>,
}let book1 = Book { title: "Rust".to_string(), subtitle: None };
let json1 = serde_json::to_string(&book1).unwrap(); // {"title":"Rust"}let book2 = Book { title: "Rust".to_string(), subtitle: Some("Advanced".to_string()) };
let json2 = serde_json::to_string(&book2).unwrap(); // {"title":"Rust","subtitle":"Advanced"}
使用Hyper客戶端
use hyper::{Client, Body};
use hyper_tls::HttpsConnector;#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {let https = HttpsConnector::new();let client = Client::builder().build::<_, Body>(https);let uri = "https://jsonplaceholder.typicode.com/todos/1".parse()?;let resp = client.get(uri).await?;let body_bytes = hyper::body::to_bytes(resp.into_body()).await?;let body_str = String::from_utf8(body_bytes.to_vec())?;println!("Response: {}", body_str);Ok(())
}
處理日期時間
use chrono::{DateTime, Utc};#[derive(Serialize, Deserialize)]
struct Event {name: String,#[serde(with = "chrono::serde::ts_seconds")]timestamp: DateTime<Utc>,
}let event = Event {name: "Conference".to_string(),timestamp: Utc::now(),
};
let json = serde_json::to_string(&event).unwrap();
使用warp框架
use warp::Filter;#[derive(Serialize, Deserialize)]
struct Message {text: String,
}let hello = warp::path("hello").and(warp::post())