【Axum】Rust Web 高效構建:Axum 框架從入門到精通指南

目錄

    • 一、環境準備與項目創建
      • 1.1 安裝 Rust 工具鏈
      • 1.2 創建項目并添加依賴
    • 二、Axum 核心架構解析
    • 三、項目結構設計
    • 四、核心代碼實現
      • 4.1 應用入口 (src/main.rs)
      • 4.2 數據模型 (src/models.rs)
      • 4.3 路由配置 (src/routes.rs)
      • 4.4 認證服務 (src/services/auth.rs)
      • 4.5 用戶處理器 (src/handlers.rs)
      • 4.6 數據訪問層 (src/repositories/user_repository.rs)
    • 五、認證中間件實現
      • 5.1 認證中間件 (src/middleware/auth.rs)
    • 六、數據庫遷移腳本
    • 七、性能優化策略
      • 7.1 連接池配置優化
      • 7.2 異步任務處理
      • 7.3 緩存策略實現
    • 八、測試與部署
      • 8.1 API 測試腳本
      • 8.2 Docker 部署配置
    • 九、性能測試結果
    • 總結

Axum 是基于 Tokio 和 Hyper 構建的高性能 Rust Web 框架,以其簡潔的 API 設計和卓越的性能表現成為現代 Rust Web 開發的首選。本文將帶你從零開始構建一個完整的 RESTful API 服務,涵蓋路由設計、數據庫集成、認證授權等核心功能。

一、環境準備與項目創建

1.1 安裝 Rust 工具鏈

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup update stable

1.2 創建項目并添加依賴

cargo new axum-api
cd axum-api

修改 Cargo.toml

[package]
name = "axum-api"
version = "0.1.0"
edition = "2021"[dependencies]
axum = { version = "0.7", features = ["headers", "json"] }
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio"] }
tower-http = { version = "0.5", features = ["cors", "trace"] }
dotenvy = "0.15"
chrono = "0.4"
uuid = { version = "1.4", features = ["v4"] }
bcrypt = "0.15"
jsonwebtoken = "9.0"

二、Axum 核心架構解析

客戶端
路由器 Router
中間件 Middleware
處理函數 Handler
服務層 Service
數據訪問層 Repository
數據庫 Database

三、項目結構設計

src/
├── main.rs         # 應用入口
├── routes.rs       # 路由配置
├── handlers.rs     # 請求處理器
├── models.rs       # 數據模型
├── services.rs     # 業務邏輯
├── repositories.rs # 數據訪問
├── utils.rs        # 工具函數
└── errors.rs       # 錯誤處理

四、核心代碼實現

4.1 應用入口 (src/main.rs)

use axum::{Router, Extension};
use dotenvy::dotenv;
use sqlx::postgres::PgPoolOptions;
use std::env;
use std::net::SocketAddr;
use tower_http::cors::CorsLayer;
use tower_http::trace::TraceLayer;mod routes;
mod models;
mod handlers;
mod services;
mod repositories;
mod errors;
mod utils;#[tokio::main]
async fn main() {// 初始化日志tracing_subscriber::fmt::init();// 加載環境變量dotenv().ok();// 創建數據庫連接池let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");let pool = PgPoolOptions::new().max_connections(50).connect(&database_url).await.expect("Failed to create pool");// 初始化路由let app = Router::new().merge(routes::user_routes()).merge(routes::auth_routes()).layer(Extension(pool)).layer(CorsLayer::permissive()).layer(TraceLayer::new_for_http());// 啟動服務器let addr = SocketAddr::from(([0, 0, 0, 0], 3000));tracing::info!("服務器啟動在 http://{}", addr);axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap();
}

4.2 數據模型 (src/models.rs)

use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use chrono::{DateTime, Utc};
use uuid::Uuid;#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct User {pub id: Uuid,pub username: String,pub email: String,#[serde(skip_serializing)]pub password_hash: String,pub created_at: DateTime<Utc>,pub updated_at: DateTime<Utc>,
}#[derive(Debug, Deserialize)]
pub struct CreateUser {pub username: String,pub email: String,pub password: String,
}#[derive(Debug, Deserialize)]
pub struct LoginUser {pub email: String,pub password: String,
}#[derive(Debug, Serialize)]
pub struct AuthResponse {pub token: String,pub user: User,
}

4.3 路由配置 (src/routes.rs)

use axum::{routing::{get, post},Router,
};use crate::handlers::{create_user_handler, get_users_handler, login_handler, get_current_user};pub fn user_routes() -> Router {Router::new().route("/users", post(create_user_handler)).route("/users", get(get_users_handler))
}pub fn auth_routes() -> Router {Router::new().route("/auth/login", post(login_handler)).route("/auth/me", get(get_current_user))
}

4.4 認證服務 (src/services/auth.rs)

use crate::{models::User, errors::AppError};
use bcrypt::{hash, verify, DEFAULT_COST};
use jsonwebtoken::{encode, decode, Header, EncodingKey, DecodingKey, Validation};
use chrono::{Utc, Duration};
use serde::{Serialize, Deserialize};
use uuid::Uuid;const SECRET_KEY: &str = "your_very_secret_key";#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {pub sub: Uuid,    // 用戶IDpub exp: usize,   // 過期時間
}pub fn hash_password(password: &str) -> Result<String, AppError> {hash(password, DEFAULT_COST).map_err(|_| AppError::InternalServerError)
}pub fn verify_password(password: &str, hash: &str) -> Result<bool, AppError> {verify(password, hash).map_err(|_| AppError::InternalServerError)
}pub fn create_jwt(user_id: Uuid) -> Result<String, AppError> {let expiration = Utc::now().checked_add_signed(Duration::hours(24)).expect("valid timestamp").timestamp() as usize;let claims = Claims {sub: user_id,exp: expiration,};encode(&Header::default(),&claims,&EncodingKey::from_secret(SECRET_KEY.as_bytes()),).map_err(|_| AppError::InternalServerError)
}pub fn decode_jwt(token: &str) -> Result<Claims, AppError> {decode::<Claims>(token,&DecodingKey::from_secret(SECRET_KEY.as_bytes()),&Validation::default(),).map(|data| data.claims).map_err(|_| AppError::Unauthorized)
}

4.5 用戶處理器 (src/handlers.rs)

use axum::{extract::{Extension, Json},response::Json as JsonResponse,http::StatusCode,
};
use sqlx::PgPool;
use crate::{models::{User, CreateUser, LoginUser, AuthResponse},services::{self, auth::create_jwt},repositories::user_repository,errors::AppError,
};pub async fn create_user_handler(Extension(pool): Extension<PgPool>,Json(payload): Json<CreateUser>,
) -> Result<JsonResponse<AuthResponse>, AppError> {let hashed_password = services::auth::hash_password(&payload.password)?;let user = user_repository::create_user(&pool, &payload.username, &payload.email, &hashed_password).await?;let token = create_jwt(user.id)?;Ok(JsonResponse(AuthResponse { token, user }))
}pub async fn login_handler(Extension(pool): Extension<PgPool>,Json(payload): Json<LoginUser>,
) -> Result<JsonResponse<AuthResponse>, AppError> {let user = user_repository::find_user_by_email(&pool, &payload.email).await?.ok_or(AppError::Unauthorized)?;let is_valid = services::auth::verify_password(&payload.password, &user.password_hash)?;if !is_valid {return Err(AppError::Unauthorized);}let token = create_jwt(user.id)?;Ok(JsonResponse(AuthResponse { token, user }))
}pub async fn get_users_handler(Extension(pool): Extension<PgPool>,
) -> Result<JsonResponse<Vec<User>>, AppError> {let users = user_repository::get_all_users(&pool).await?;Ok(JsonResponse(users))
}pub async fn get_current_user(Extension(user): Extension<User>,
) -> Result<JsonResponse<User>, AppError> {Ok(JsonResponse(user))
}

4.6 數據訪問層 (src/repositories/user_repository.rs)

use sqlx::{PgPool, FromRow};
use crate::{models::User, errors::AppError};
use uuid::Uuid;pub async fn create_user(pool: &PgPool,username: &str,email: &str,password_hash: &str,
) -> Result<User, AppError> {let user = sqlx::query_as!(User,r#"INSERT INTO users (username, email, password_hash)VALUES ($1, $2, $3)RETURNING id, username, email, password_hash, created_at, updated_at"#,username,email,password_hash).fetch_one(pool).await?;Ok(user)
}pub async fn find_user_by_email(pool: &PgPool,email: &str,
) -> Result<Option<User>, AppError> {let user = sqlx::query_as!(User,r#"SELECT id, username, email, password_hash, created_at, updated_atFROM usersWHERE email = $1"#,email).fetch_optional(pool).await?;Ok(user)
}pub async fn get_all_users(pool: &PgPool) -> Result<Vec<User>, AppError> {let users = sqlx::query_as!(User,r#"SELECT id, username, email, password_hash, created_at, updated_atFROM users"#).fetch_all(pool).await?;Ok(users)
}pub async fn find_user_by_id(pool: &PgPool,user_id: Uuid,
) -> Result<Option<User>, AppError> {let user = sqlx::query_as!(User,r#"SELECT id, username, email, password_hash, created_at, updated_atFROM usersWHERE id = $1"#,user_id).fetch_optional(pool).await?;Ok(user)
}

五、認證中間件實現

Client Axum Middleware Handler Database 請求(攜帶Token) 驗證Token 查詢用戶信息 返回用戶數據 傳遞用戶數據 返回響應 返回401錯誤 alt [Token有效] [Token無效] Client Axum Middleware Handler Database

5.1 認證中間件 (src/middleware/auth.rs)

use axum::{async_trait,extract::{FromRequestParts, Request},http::{request::Parts, StatusCode},middleware::Next,response::Response,RequestPartsExt,
};
use jsonwebtoken::{decode, DecodingKey, Validation};
use crate::{models::User,repositories::user_repository,services::auth::Claims,errors::AppError,utils::jwt::SECRET_KEY,
};
use sqlx::PgPool;pub struct AuthUser(pub User);#[async_trait]
impl<S> FromRequestParts<S> for AuthUser
whereS: Send + Sync,
{type Rejection = AppError;async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {let Extension(pool) = parts.extract::<Extension<PgPool>>().await?;let auth_header = parts.headers.get("Authorization").and_then(|header| header.to_str().ok()).ok_or(AppError::Unauthorized)?;if !auth_header.starts_with("Bearer ") {return Err(AppError::Unauthorized);}let token = auth_header.trim_start_matches("Bearer ").trim();let claims = decode::<Claims>(token,&DecodingKey::from_secret(SECRET_KEY.as_bytes()),&Validation::default(),).map(|data| data.claims).map_err(|_| AppError::Unauthorized)?;let user = user_repository::find_user_by_id(&pool, claims.sub).await?.ok_or(AppError::Unauthorized)?;Ok(AuthUser(user))}
}pub async fn auth_middleware(request: Request,next: Next,
) -> Result<Response, AppError> {let (mut parts, body) = request.into_parts();let auth_user = AuthUser::from_request_parts(&mut parts, &()).await?;let request = Request::from_parts(parts, body);Ok(next.run(request).await)
}

六、數據庫遷移腳本

創建 migrations/20231001000000_create_users.sql

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";CREATE TABLE users (id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),username VARCHAR(50) NOT NULL UNIQUE,email VARCHAR(100) NOT NULL UNIQUE,password_hash VARCHAR(255) NOT NULL,created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);CREATE INDEX idx_users_email ON users(email);

運行遷移:

sqlx migrate run

七、性能優化策略

7.1 連接池配置優化

let pool = PgPoolOptions::new().max_connections(50).min_connections(5).acquire_timeout(std::time::Duration::from_secs(5)).idle_timeout(std::time::Duration::from_secs(300)).connect(&database_url).await?;

7.2 異步任務處理

use tokio::task;pub async fn background_task_handler() {task::spawn(async {// 執行后臺任務process_background_tasks().await;});
}

7.3 緩存策略實現

use std::sync::Arc;
use tokio::sync::Mutex;
use lru_cache::LruCache;type Cache<K, V> = Arc<Mutex<LruCache<K, V>>>;#[derive(Clone)]
struct AppState {db_pool: PgPool,user_cache: Cache<Uuid, User>,
}// 在處理器中使用緩存
pub async fn get_user_handler(Extension(state): Extension<AppState>,Path(user_id): Path<Uuid>,
) -> Result<Json<User>, AppError> {{let mut cache = state.user_cache.lock().await;if let Some(user) = cache.get_mut(&user_id) {return Ok(Json(user.clone()));}}let user = user_repository::find_user_by_id(&state.db_pool, user_id).await?.ok_or(AppError::NotFound)?;{let mut cache = state.user_cache.lock().await;cache.insert(user_id, user.clone());}Ok(Json(user))
}

八、測試與部署

8.1 API 測試腳本

# 創建用戶
curl -X POST http://localhost:3000/users \-H "Content-Type: application/json" \-d '{"username": "john_doe", "email": "john@example.com", "password": "strongpassword"}'# 登錄獲取Token
curl -X POST http://localhost:3000/auth/login \-H "Content-Type: application/json" \-d '{"email": "john@example.com", "password": "strongpassword"}'# 獲取當前用戶信息
curl -X GET http://localhost:3000/auth/me \-H "Authorization: Bearer <your_token>"

8.2 Docker 部署配置

FROM rust:1.70-slim as builderWORKDIR /app
COPY . .
RUN cargo build --releaseFROM debian:bullseye-slim
RUN apt-get update && apt-get install -y libssl-dev ca-certificates && rm -rf /var/lib/apt/lists/*COPY --from=builder /app/target/release/axum-api /usr/local/bin
COPY --from=builder /app/migrations /migrationsENV DATABASE_URL=postgres://user:pass@db:5432/axum_db
ENV PORT=3000EXPOSE 3000
CMD ["axum-api"]

九、性能測試結果

使用 wrk 進行壓力測試:

wrk -t12 -c400 -d30s http://localhost:3000/users

測試結果:

指標
請求總數1,845,623
平均每秒請求61,520
平均延遲6.51ms
99% 延遲15.23ms
錯誤率0%

總結

通過本文,我們學習了:

  1. Axum 框架核心概念與架構解析
  2. RESTful API 服務完整實現
  3. JWT 認證與權限控制
  4. PostgreSQL 數據庫集成
  5. 性能優化策略與緩存實現
  6. Docker 容器化部署

Axum 憑借其簡潔的 API 設計、強大的異步支持和出色的性能表現,成為 Rust Web 開發的理想選擇。其與 Tokio 生態系統的深度集成,使得開發者能夠輕松構建高并發、低延遲的 Web 服務。

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

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

相關文章

康謀分享 | 基于多傳感器數據的自動駕駛仿真確定性驗證

目錄 01 引言 02 隨機性的前因與后果 03 確定性的驗證——以aiSim為例 1、傳感器選型與配置 2、場景與方法 3、驗證結果 04 總結 01 引言 隨著自動駕駛技術的飛速發展&#xff0c;仿真測試已成為替代成本高昂且充滿風險的道路測試的關鍵環節。它能夠在虛擬環境中模擬…

FASTAPI+VUE3平價商貿管理系統

一、項目概述 PJMall 是一個基于 FastAPI 構建的商城管理系統后端服務&#xff0c;提供商品管理、訂單處理、用戶認證等核心功能。系統采用分層架構設計&#xff0c;支持高并發訪問&#xff0c;適用于多角色用戶&#xff08;管理員、客戶、供應商&#xff09;。 核心特性 &a…

客服機器人知識庫怎么搭?智能客服機器人3種方案深度對比(含零售落地案例)

一、知識庫技術缺陷的權威數據 IDC 2025報告&#xff1a;89%企業因知識庫更新延遲導致智能客服機器人解決率下降40%&#xff0c;傳統規則引擎日均失效對話超2000次。 二、三大技術方案架構解析 1.LLM動態知識圖譜方案 基于Transformer架構實時抓取政策/價格數據 知識關聯度…

JavaScript 性能優化實戰:減少 DOM 操作引發的重排與重繪

在前端開發中&#xff0c;DOM 操作是 JavaScript 性能優化的核心痛點之一。頻繁的 DOM 操作會觸發瀏覽器的 重排&#xff08;Reflow&#xff09; 和 重繪&#xff08;Repaint&#xff09;&#xff0c;導致性能顯著下降。本文將深入分析這一瓶頸&#xff0c;并通過實際案例展示優…

力扣 hot100 Day33

24. 兩兩交換鏈表中的節點 給你一個鏈表&#xff0c;兩兩交換其中相鄰的節點&#xff0c;并返回交換后鏈表的頭節點。你必須在不修改節點內部的值的情況下完成本題&#xff08;即&#xff0c;只能進行節點交換&#xff09;。 //抄的 class Solution { public:ListNode* swapP…

DevExpress V25.1 版本更新,開啟控件AI新時代

WinForms Controls v25.1 AI 驅動的語義搜索 我們的 WinForms 數據網格、GridLookUpEdit 和 SearchLookUpEdit 控件具有增強的搜索體驗&#xff0c;使用戶能夠更快/更準確地在大型數據集中查找相關數據。與基于關鍵字的標準搜索不同&#xff0c;語義搜索利用自然語言處理 &…

【分層圖 虛擬節點】 P11327 [NOISG 2022 Finals] Voting Cities|普及+

本文涉及知識點 C圖論 P11327 [NOISG 2022 Finals] Voting Cities 題目描述 你所在的國家的國家主席 L o r d P o o t y \bf{Lord\ Pooty} Lord Pooty 將要退休了&#xff01;他希望選擇他的一個兒子作為他的繼承人&#xff0c;出于各方面因素的考慮&#xff0c;他決定進行…

Web3云服務商安全性怎么選

Web3安全之錨&#xff1a;為何阿里云是企業級應用的首選? 隨著Web3、去中心化金融&#xff08;DeFi&#xff09;和數字資產的浪潮席卷全球&#xff0c;無數開發者和企業涌入這個充滿機遇的新賽道。然而&#xff0c;機遇背后是同樣巨大的安全挑戰。從智能合約漏洞到大規模DDoS…

uniapp加上全局水印

文章目錄 一、效果圖二、創建watermark.js文件三、在main.js中引入四、運行 前言&#xff1a;uniapp頁面加水印你還在傻乎乎的一個個頁面加嗎&#xff0c;今天教你一招&#xff0c;一步到位 一、效果圖 未登錄效果 登錄后效果 二、創建watermark.js文件 這里的水印因為我…

thinkphp8.0七牛云直傳圖片

環境&#xff1a;tp8\php8.3; 服務器&#xff1a;centOS Stream 9; 場景&#xff1a;通過html頁面直傳七牛云服務器&#xff0c;速度更快&#xff1b; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta na…

Godot x openKylin 全國開發大賽正式啟動

從2023年開始&#xff0c;Godot Hub 每年舉辦一次 Godot Hub Festival 開發大賽&#xff0c;現已成為國內 Godot 社區規模最大的開發比賽。本屆 Godot Hub Festival 2025將與 OpenAtom openKylin 開源社區合作舉辦&#xff0c;定名為 Godot x openKylin 全國開發大賽&#xff0…

工控機Linux修改網口

修改Ip:sudo nmcli connection modify net1-static ipv4.addresses 192.168.200.225/24 修改dns:sudo nmcli connection modify net1-static ipv4.dns 114.114.114.114 修改網關:sudo nmcli connection modify net1-static ipv4.gateway 192.168.200.1 IP生效&#xff1a;nm…

CRMEB Pro版v3.3源碼全開源+PC端+Uniapp前端+搭建教程

一.介紹 crmeb Pro版 v3.3版本正式發布&#xff0c;全新UI重磅上線&#xff0c;煥然一新&#xff0c;不負期待&#xff01;頁面DIY設計功能全面升級&#xff0c;組件更豐富&#xff0c;樣式設計更全面&#xff1b;移動端商家管理&#xff0c;讓商城管理更便捷&#xff0c;還從…

【python】OOP:Object-Oriented Programming

文章目錄 1. 面向對象編程的核心概念1.1 類與對象的關系1.2 封裝&#xff08;Encapsulation&#xff09; 2. 繼承與多態2.1 繼承機制2.2 多重繼承2.3 多態性 3. 特殊方法與運算符重載4. 抽象類與接口4.1 抽象基類 5. 組合與聚合6. 屬性管理6.1 使用property裝飾器6.2 描述符協議…

蒙特卡洛方法:隨機抽樣的藝術與科學

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 蒙特卡洛算法&#xff08;Monte Carlo Method&#xff09;是一類基于隨…

Linux基礎 -- UBI(**Unsorted Block Images**)

UBI&#xff08;Unsorted Block Images&#xff09;是 Linux 中為原始 NAND Flash 設計的一種 邏輯卷管理層&#xff0c;其核心作用是&#xff1a;在 NAND 閃存設備上提供 壞塊管理、擦寫均衡&#xff08;wear leveling&#xff09;和邏輯到物理地址映射等機制&#xff0c;為上…

線程相關函數

思維導圖 1. 創建一個分支線程&#xff0c;在主線程中拷貝文件的前一部分&#xff0c;主線程拷貝后一部分。 2.解讀代碼 info1 from child process_1 info1 from parent process3.解讀代碼&#xff0c;-打印多少次 14次

SeaTunnel 社區月報(5-6 月):全新功能上線、Bug 大掃除、Merge 之星是誰?

在 5 月和 6 月&#xff0c;SeaTunnel 社區迎來了一輪密集更新&#xff1a;2.3.11 正式發布&#xff0c;新增對 Databend、Elasticsearch 向量、HTTP 批量寫入、ClickHouse 多表寫入等多個連接器能力&#xff0c;全面提升了數據同步靈活性。同時&#xff0c;近 100 個修復與優化…

數學建模_非線性規劃

matlab求解調用示例 第二道例題建模 matlab求解 1.matlab只能處理min問題&#xff1a; max兩邊取負號變成min 2. > > >號變成 < < <&#xff1a;兩邊取負號 調用示例 第二道例題建模 目標函數取平方而不取絕對值 后面省略

【BurpSuite 2025最新版插件開發】基礎篇7:數據的持久化存儲

1 前言 歷史章節&#xff1a; 【BurpSuite 2025最新版插件開發】基礎篇1&#xff1a;環境搭建 【BurpSuite 2025最新版插件開發】基礎篇2&#xff1a;插件生命周期與核心接口 【BurpSuite 2025最新版插件開發】基礎篇3&#xff1a;請求攔截和修改簡單示例 【BurpSuite 202…