基于 Rust 的Actix Web 框架的應用與優化實例

基于 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
}

關鍵組件

  1. 路由與處理函數

    • 使用 #[get]#[post] 等宏定義路由。
    • 處理函數返回 impl Responder,支持多種響應類型(如 HttpResponseString)。
  2. 狀態共享
    通過 Data<T> 類型共享全局狀態(如數據庫連接池):

    App::new().app_data(Data::new(AppState { db: pool }))
    
  3. 中間件
    使用 wrap 添加中間件(如日志、認證):

    App::new().wrap(Logger::default())
    
  4. 錯誤處理
    自定義錯誤類型并實現 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請求與響應處理的實用示例集合,涵蓋常見場景和庫(如serdereqwestactix-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())

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/90448.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/90448.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/90448.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

springMVC01-特點、創建項目、@RequestMapping、獲取參數請求,三種域對象

一、簡介 SpringMVC 就是 Spring 框架中的 MVC 模塊&#xff0c;用于構建 Web 應用中的“控制層”。 SpringMVC 是 Spring 提供的一個基于 Servlet 的 Web MVC 框架模塊&#xff0c;是 Spring 整個體系中的“Web 層核心”。 SpringMVC 是 Spring 的一部分&#xff0c;Spring…

Java基礎,反射破壞封裝性 - 單例模式的崩塌

目錄一、容易出現問題的小李代碼小李的單例設計看似完美&#xff0c;實則存在三個致命問題&#xff1a;1、反射攻擊的天然漏洞2、序列化的隱患3、性能瓶頸二、隔壁老王的優化方案三、為什么這樣優化&#xff1f;四、小結周五下午&#xff0c;代碼審查會議上&#xff0c;小李自信…

Neo4j 綜合練習作業

Neo4j 綜合練習作業 作業說明 這個作業涵蓋了 Neo4j 的多個重要知識點&#xff0c;包括節點和關系的創建、查詢、更新、刪除以及高級查詢功能。請使用 Cypher 語句完成以下所有題目。 數據準備 首先執行以下語句創建示例數據&#xff1a; ACTED_IN: 表示出演關系 DIRECTED: 表示…

基于PA算法的FTL引導

一、抽象綁定關系 1. 什么是 AF Block,什么是 NF Block,為什么要將多個 NF Block 綁定為一個 AF Block AF Block(Allocation Flash Block) 和 NF Block(NAND Flash Block) 是在 NAND Flash 存儲架構中用于管理數據的基本單位。 AF Block 定義:AF Block 是一組多個 NF…

快速入門Java中的IO操作

以下是 Java 中常用的 IO 知識點總結&#xff1a; 1. 流的分類 按數據流向&#xff1a;輸入流&#xff08;讀取數據&#xff09;和輸出流&#xff08;寫入數據&#xff09;。按數據類型&#xff1a;字節流&#xff08;處理二進制數據&#xff0c;以字節為單位&#xff09;和字符…

小程序軟裝: 組件庫開發

本節概述 經過前面小節的學習&#xff0c;我們已經搭建起了小程序的編譯構建環境&#xff0c;能夠將我們開發的小程序項目編譯成為對應的邏輯代碼文件 logic.js&#xff0c;頁面渲染文件 view.js&#xff0c;樣式文件 style.css 和配置文件 config.json 在編譯小程序的過程中…

250708-Debian系統安裝Edge瀏覽器并配置最小中文輸入法

在 Debian 系統上安裝 Microsoft Edge 瀏覽器可以通過以下幾種方式進行。Microsoft 官方提供了 .deb 安裝包&#xff0c;適用于 Debian、Ubuntu 及其衍生系統。 A. 如何安裝&#xff1f; ? 方法一&#xff1a;使用 .deb 安裝包&#xff08;推薦&#xff09; 步驟 1&#xff…

docker所占硬盤內存指令

使用下面命令可以查看docker所占的硬盤大小&#xff0c;如&#xff1a;docker system dfdocker system df -v

A1126LLHLX-T Allegro霍爾效應鎖存器,5kHz+推挽輸出,汽車級轉速檢測專家!

A1126LLHLX-T&#xff08;Allegro&#xff09;產品解析一、產品定位A1126LLHLX-T是Allegro MicroSystems推出的全極性霍爾效應鎖存器&#xff0c;采用超薄SOT-23W封裝&#xff08;1mm厚度&#xff09;&#xff0c;專為高可靠性位置檢測與轉速測量設計&#xff0c;具有低功耗、高…

【C#】File從后往前讀取文件指定行數

/// <summary>/// 從后往前讀取文件最后行數據/// </summary>/// <param name"filePath"></param>/// <param name"count"></param>/// <returns></returns>public static List<string> ReadFileRe…

暑假算法日記第五天

目標?&#xff1a;刷完靈神專題訓練算法題單 階段目標&#x1f4cc;&#xff1a;【算法題單】滑動窗口與雙指針 LeetCode題目:683. K 個關閉的燈泡2067. 等計數子串的數量2524. 子數組的最大頻率分數2269. 找到一個數字的 K 美麗值1984. 學生分數的最小差值1461. 檢查一個字符…

【05】MFC入門到精通——MFC 為對話框中的控件添加變量 和 數據交換和檢驗

文章目錄四、 為對話框中的控件添加變量五、對話框類的5.1 為編輯框添加變量面步驟中 為對話框添加了幾個控件&#xff0c;包括三個靜態文本框&#xff0c;三個編輯框&#xff0c;一個按鈕控件。 四、 為對話框中的控件添加變量 編輯框中的數據可能會經常變化&#xff0c;有必…

4-Kafka-partition(分區)概念

Kafka Topic 分區詳解 &#x1f4cc; 一、分區核心概念 1. 什么是分區&#xff1f; 物理分片&#xff1a;Topic 被劃分為多個分區&#xff08;Partition&#xff09;&#xff0c;每個分區是一個有序、不可變的消息序列存儲單位&#xff1a;每個分區對應一個物理日志文件&…

論文略讀:UniPELT: A Unified Framework for Parameter-Efficient Language Model Tuning

ACL 2021 LoRAPrefix TuningAdapter門控藍色參數是可訓練的參數

【論文閱讀】CogView: Mastering Text-to-Image Generation via Transformers

CogView&#xff1a;通過Transformers實現文本到圖像的生成簡介目標&#xff1a;通用領域中的文本到圖像生成一直是一個開放的問題&#xff0c;它既需要強大的生成模型&#xff0c;也需要跨模態的理解。為了解決這個問題&#xff0c;我們提出了CogView&#xff0c;一個具有VQ -…

Typecho與WordPress技術架構深度對比:從LAMP到輕量級設計

文章目錄 Typecho vs WordPress:深入比較兩大博客系統的優劣與選型指南引言1. 系統概述與技術架構1.1 WordPress架構分析1.2 Typecho架構特點2. 核心功能對比2.1 內容管理能力2.2 主題與模板系統3. 性能與擴展性對比3.1 系統性能基準測試3.2 擴展生態系統4. 安全性與維護成本4…

CSS揭秘:8.連續的圖像邊框

前置知識&#xff1a;CSS 漸變&#xff0c;5. 條紋背景&#xff0c;border-image&#xff0c;基本的 CSS 動畫前言 本文旨在實現圖片邊框效果&#xff0c;即在特定場景下讓圖片顯示在邊框而非背景區域。 一、傳統實現方案 正常我們面對這樣一個需求時&#xff0c;下意識會想到的…

Linux驅動學習day20(pinctrl子系統驅動大全)

一、Pinctrl作用Pinctrl(Pin Controller)&#xff1a;控制引腳引腳的枚舉與命名、引腳復用、引腳配置。Pinctrl驅動一般由芯片原廠的BSP工程師來寫&#xff0c;一般驅動工程師只需要在設備樹中指明使用哪個引腳&#xff0c;復用為哪個功能、配置為哪些狀態。二、Pin Controller…

Debiased All-in-one Image Restoration with Task Uncertainty Regularization

Abstract 一體化圖像恢復是一項基礎的底層視覺任務&#xff0c;在現實世界中有重要應用。主要挑戰在于在單個模型中處理多種退化情況。雖然當前方法主要利用任務先驗信息來指導恢復模型&#xff0c;但它們通常采用統一的多任務學習&#xff0c;忽略了不同退化任務在模型優化中的…

逆向 qq 音樂 sign,data, 解密 response 返回的 arraybuffer

解密 arraybuffer python requests 請求得到 arraybuffer&#xff0c;轉為 hex 傳遞給 js res_data sign ctx.call("decrypt", response.content.hex())function decrypt(hex) {const bytes new Uint8Array(hex.length / 2);for (let i 0; i < hex.length; i …