從零開始使用 axum-server 構建 HTTP/HTTPS 服務

axum-server 是 Rust 生態中為 axum 框架設計的高性能服務器實現,基于 hyper(底層 HTTP 引擎)和 tower(服務抽象)構建,支持 HTTP/1、HTTP/2 及 HTTPS。本教程將從環境準備到實戰功能,一步步帶你掌握 axum-server 的使用。

1. 環境準備:安裝 Rust 與工具鏈

首先需要搭建 Rust 開發環境,這是運行 axum-server 項目的基礎。

步驟 1:安裝 Rust

打開終端,執行官方安裝腳本(適用于 Windows/macOS/Linux):

# 安裝 Rust 工具鏈(包含 cargo、rustc 等)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

按照提示完成安裝,最后執行以下命令讓環境變量生效:

# Linux/macOS
source $HOME/.cargo/env
# Windows(PowerShell)
$env:Path += ";$HOME\.cargo\bin"

步驟 2:驗證環境

執行以下命令,確認 Rust 與 Cargo 安裝成功:

rustc --version  # 應顯示 Rust 版本(建議 1.70+)
cargo --version  # 應顯示 Cargo 版本

2. 第一個項目:Hello World 服務

我們從最簡單的 HTTP 服務開始,實現 “訪問指定地址返回 Hello World” 的功能。

步驟 1:創建新項目

打開終端,執行以下命令創建名為?axum-server-demo?的 Rust 項目:

cargo new axum-server-demo
cd axum-server-demo

步驟 2:添加依賴

修改項目根目錄下的?Cargo.toml?文件,添加?axumaxum-server?和?tokio(異步運行時)的依賴:

[package]
name = "axum-server-demo"
version = "0.1.0"
edition = "2021"[dependencies]
# axum 框架:用于定義路由和處理請求
axum = "0.7"
# axum-server:核心服務器實現
axum-server = "0.7"
# tokio:異步運行時(axum/axum-server 依賴異步)
tokio = { version = "1.0", features = ["full"] }
# 用于處理網絡地址(SocketAddr)
std-sys = "0.1"  # 或直接使用 std 的 net 模塊(無需額外依賴,本示例用 std)

步驟 3:編寫核心代碼

打開?src/main.rs?文件,替換為以下代碼(關鍵步驟已加注釋):

// 1. 導入所需模塊
use axum::{routing::get, Router};  // axum 的路由與路由器
use axum_server::Server;          // axum-server 的核心服務器類型
use std::net::SocketAddr;         // 標準庫的網絡地址類型// 2. 異步主函數(axum/axum-server 基于異步,需用 tokio::main 宏)
#[tokio::main]
async fn main() {// 3. 定義路由:訪問根路徑(/)時,用 GET 方法觸發 handler// handler 是一個異步函數,返回 "Hello, axum-server!"let app = Router::new().route("/", get(|| async { "Hello, axum-server!" }));// 4. 定義服務器監聽地址:127.0.0.1(本地回環),端口 3000let addr = SocketAddr::from(([127, 0, 0, 1], 3000));println!("服務器已啟動,監聽地址:http://{}", addr);// 5. 創建并啟動服務器// - bind(addr):綁定監聽地址,生成 Server 實例// - serve(app.into_make_service()):將 axum 的 Router 轉換為 tower 的 MakeService(axum-server 要求)// - await:異步等待服務器運行(阻塞主線程,直到服務器停止)// - unwrap():簡化錯誤處理(生產環境需替換為 proper error handling)Server::bind(addr).serve(app.into_make_service()).await.unwrap();
}

步驟 4:運行與測試

(1)啟動服務器:在項目根目錄執行以下命令:

cargo run

終端會輸出:服務器已啟動,監聽地址:http://127.0.0.1:3000

(2)測試服務

  • 方法 1:打開瀏覽器,訪問?http://127.0.0.1:3000,頁面會顯示?Hello, axum-server!
  • 方法 2:用終端執行?curl http://127.0.0.1:3000,會返回同樣的字符串。

3. 進階功能 1:多路由與請求處理

實際項目中需要多個路由,我們擴展示例,添加 “獲取用戶信息”“處理 POST 請求” 的功能。

步驟 1:更新代碼(支持多路由與 JSON)

修改?src/main.rs,添加 JSON 處理依賴(需先在?Cargo.toml?中添加?serde):

# 在 Cargo.toml 的 [dependencies] 中添加
serde = { version = "1.0", features = ["derive"] }  # 用于 JSON 序列化/反序列化
axum::extract::Json = "0.7"  # axum 內置的 JSON 提取器(無需額外依賴,已包含在 axum 中)

然后更新?src/main.rs?代碼:

use axum::{extract::Json,  // 提取 JSON 請求體routing::{get, post},  // 支持 GET 和 POST 方法Router,
};
use axum_server::Server;
use serde::Serialize;  // 用于序列化響應
use std::net::SocketAddr;// 定義用戶信息結構體(用于響應 JSON)
#[derive(Serialize)]
struct User {id: u32,name: String,email: String,
}// 定義 POST 請求體結構體(用于接收客戶端數據)
#[derive(serde::Deserialize)]
struct CreateUserRequest {name: String,email: String,
}// 異步 handler:獲取指定 ID 的用戶信息(路徑參數:id)
async fn get_user(id: axum::extract::Path<u32>) -> Json<User> {// 模擬從數據庫獲取用戶(實際項目中替換為真實邏輯)let user = User {id: id.0,  // 提取路徑參數中的 IDname: "Alice".to_string(),email: "alice@example.com".to_string(),};Json(user)  // 返回 JSON 格式的用戶信息
}// 異步 handler:創建用戶(接收 JSON 請求體)
async fn create_user(Json(req): Json<CreateUserRequest>) -> Json<User> {// 模擬創建用戶(實際項目中需保存到數據庫)let new_user = User {id: 100,  // 模擬自動生成的 IDname: req.name,email: req.email,};Json(new_user)  // 返回創建后的用戶信息
}#[tokio::main]
async fn main() {// 定義多路由let app = Router::new().route("/", get(|| async { "Hello, axum-server!" }))  // 根路徑.route("/users/:id", get(get_user))  // 獲取用戶(路徑參數 :id).route("/users", post(create_user));  // 創建用戶(POST 請求)let addr = SocketAddr::from(([127, 0, 0, 1], 3000));println!("服務器已啟動,監聽地址:http://{}", addr);Server::bind(addr).serve(app.into_make_service()).await.unwrap();
}

步驟 2:測試多路由

(1)啟動服務器cargo run

(2)測試根路徑curl http://127.0.0.1:3000?→ 返回?Hello, axum-server!

(3)測試獲取用戶curl http://127.0.0.1:3000/users/123?→ 返回 JSON:

{"id":123,"name":"Alice","email":"alice@example.com"}

(4)測試創建用戶(POST 請求):

curl -X POST -H "Content-Type: application/json" -d '{"name":"Bob","email":"bob@example.com"}' http://127.0.0.1:3000/users

返回 JSON(創建后的用戶):

{"id":100,"name":"Bob","email":"bob@example.com"}

4. 進階功能 2:啟用 HTTPS(基于 rustls)

實際項目中需用 HTTPS 保證安全,axum-server 支持基于?rustls?的 HTTPS,我們來實現它。

步驟 1:準備 TLS 證書

首先需要生成本地測試證書(生產環境需從 CA 機構申請),推薦用?mkcert?工具:

  1. 安裝 mkcert

    • macOS:brew install mkcert
    • Windows:choco install mkcert(需先安裝 Chocolatey)
    • Linux:sudo apt install libnss3-tools && curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" && chmod +x mkcert-v*-linux-amd64 && sudo mv mkcert-v*-linux-amd64 /usr/local/bin/mkcert
  2. 生成證書
    在項目根目錄執行以下命令,生成?localhost.pem(證書)和?localhost-key.pem(私鑰):

mkcert -install  # 安裝本地 CA(僅首次需要)
mkcert localhost 127.0.0.1  # 生成針對本地地址的證書

步驟 2:添加 HTTPS 依賴

修改?Cargo.toml,添加?axum-server?的?tls-rustls?特性:

[dependencies]
# 其他依賴不變...
axum-server = { version = "0.7", features = ["tls-rustls"] }  # 啟用 rustls 支持
rustls-pemfile = "1.0"  # 用于讀取 PEM 格式的證書/私鑰

步驟 3:修改代碼啟用 HTTPS

更新?src/main.rs,替換服務器啟動邏輯為 HTTPS 版本:

// 新增導入
use axum_server::tls_rustls::RustlsConfig;
use rustls_pemfile::{certs, pkcs8_private_keys};
use std::fs::File;
use std::io::BufReader;// 其他代碼(路由、handler)不變...#[tokio::main]
async fn main() {// 1. 讀取 TLS 證書和私鑰let cert_file = File::open("localhost.pem").unwrap();  // 證書文件路徑let key_file = File::open("localhost-key.pem").unwrap();  // 私鑰文件路徑// 2. 解析證書(PEM 格式)let cert_chain = certs(&mut BufReader::new(cert_file)).unwrap().into_iter().map(|cert| rustls::Certificate(cert)).collect();// 3. 解析私鑰(PKCS8 格式)let private_key = pkcs8_private_keys(&mut BufReader::new(key_file)).unwrap().into_iter().next().unwrap();let private_key = rustls::PrivateKey(private_key);// 4. 創建 Rustls 配置let tls_config = RustlsConfig::builder().with_single_cert(cert_chain, private_key).unwrap();  // 生產環境需處理錯誤// 5. 定義路由(與之前一致)let app = Router::new().route("/", get(|| async { "Hello, HTTPS!" })).route("/users/:id", get(get_user)).route("/users", post(create_user));let addr = SocketAddr::from(([127, 0, 0, 1], 3443));  // HTTPS 常用端口 443,測試用 3443println!("HTTPS 服務器已啟動,監聽地址:https://{}", addr);// 6. 啟動 HTTPS 服務器(用 bind_rustls 替代 bind)axum_server::bind_rustls(addr, tls_config).serve(app.into_make_service()).await.unwrap();
}

步驟 4:測試 HTTPS 服務

  1. 啟動服務器cargo run?→ 輸出?HTTPS 服務器已啟動,監聽地址:https://127.0.0.1:3443
  2. 測試 HTTPS 路徑
curl -k https://127.0.0.1:3443  # -k 忽略本地證書驗證(測試用)

返回?Hello, HTTPS!,表示 HTTPS 服務正常運行。

5. 進階功能 3:服務器生命周期控制(優雅關閉)

在生產環境中,需要讓服務器 “優雅關閉”(處理完現有請求后再停止,避免數據丟失),axum-server 提供?Handle?類型實現此功能。

步驟 1:更新代碼(添加優雅關閉邏輯)

修改?src/main.rs,關鍵新增?Handle?和信號監聽:

// 新增導入:用于監聽系統信號(如 Ctrl+C)
use axum_server::Handle;
use tokio::signal;
use tokio::sync::oneshot;// 其他代碼(路由、handler、TLS 配置)不變...#[tokio::main]
async fn main() {// 1. 創建 Handle(用于控制服務器關閉)let handle = Handle::new();let shutdown_handle = handle.clone();  // 克隆用于信號監聽任務// 2. 啟動信號監聽任務(獨立于服務器,監聽 Ctrl+C 或 SIGTERM)tokio::spawn(async move {// 監聽系統中斷信號(Ctrl+C)signal::ctrl_c().await.unwrap();println!("\n收到關閉信號,開始優雅關閉服務器...");// 觸發服務器優雅關閉(等待現有請求處理完成)shutdown_handle.shutdown();});// 3. 定義路由和 TLS 配置(與之前一致)let app = Router::new().route("/", get(|| async { "Hello, 優雅關閉!" })).route("/users/:id", get(get_user)).route("/users", post(create_user));let addr = SocketAddr::from(([127, 0, 0, 1], 3443));let tls_config = RustlsConfig::builder()  // 復用之前的 TLS 配置邏輯.with_single_cert(cert_chain, private_key).unwrap();// 4. 啟動服務器時綁定 Handleaxum_server::bind_rustls(addr, tls_config).handle(handle)  // 將 Handle 傳遞給服務器.serve(app.into_make_service()).await.unwrap();println!("服務器已完全關閉");
}

步驟 2:測試優雅關閉

(1)啟動服務器cargo run

(2)觸發關閉:在終端按?Ctrl+C,會看到:

收到關閉信號,開始優雅關閉服務器...
服務器已完全關閉

(3)驗證效果:如果在按?Ctrl+C?前發起一個慢請求(如模擬耗時處理),服務器會等待請求完成后再關閉,而非強制中斷。

6. 總結與進階方向

通過本教程,你已掌握 axum-server 的核心用法:

  • 搭建基礎 HTTP 服務,實現多路由與 JSON 處理;
  • 啟用 HTTPS(基于 rustls);
  • 實現服務器優雅關閉。

后續還可以增加以下內容:

  1. 錯誤處理:替換示例中的?unwrap(),用?thiserror?或?anyhow?處理實際項目中的錯誤;
  2. 生產配置:優化 TLS 配置(如啟用 TLS 1.3、添加證書鏈)、調整服務器參數(如連接數限制);
  3. 擴展功能:結合 axum 的中間件(如日志、認證)、使用?axum-server?的?from_tcp?從現有 TCP 監聽創建服務器;
  4. 性能優化:基于 hyper 的特性調整線程池、啟用 HTTP/2 優先級等。

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

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

相關文章

電路運行的核心-RTC

1. 時鐘芯片是什么&#xff1f;時鐘芯片&#xff0c;更準確的名稱是實時時鐘芯片&#xff0c;英文是 Real-Time Clock&#xff0c;簡稱 RTC。它是一個專用的集成電路&#xff0c;其核心功能是追蹤時間和日歷。你可以把它想象成電子設備里的一個“電子表”或“日歷鐘”。關鍵特性…

AR消防頭盔:火場救援的智能“透視眼”

在濃煙彌漫、能見度幾乎為零的火場中&#xff0c;消防員們依靠什么來精準掌握隊友的位置和狀態&#xff1f;答案是AR智能消防頭盔&#xff08; www.teamhelper.cn &#xff09;。這種頭盔通過多種定位技術的融合&#xff0c;為消防員提供了強大的團隊協作和指揮協同能力&#x…

基于大模型的個性化推薦系統實現探索與應用

前言 如果你一直在跟著Fanstuck博主的腳步探索AI大模型的相關內容&#xff0c;從最初的大模型Prompt工程解析&#xff0c;DeepSeek全面解析&#xff0c;到實際的私有化大模型開發部署&#xff0c;再到深入NL2SQL、知識圖譜大模型和ChatBI等更高階應用.我是Fanstuck&#xff0c…

【已解決】Echarts 力學布局圖譜切換圖例的時候線條殘留在了畫布上

在用Vue3封裝 ECharts 的力導向圖&#xff08;graph force&#xff09;時&#xff0c;我遇到一個問題&#xff1a;點擊圖例切換節點顯隱后&#xff0c;線條殘留在原位置&#xff0c;畫布出現“臟線條”。&#xff08;問題如下&#xff1a;&#xff09;這個問題本質上是因為…&…

Vue動態實時字數限制

文章目錄&#x1f680; Vue.js 動態實時字數限制指南1. 核心實現方法1.1 使用計算屬性 (Computed Property)1.2 結合計算屬性的 Setter/Getter1.3 使用監聽器 (Watcher)1.4 使用自定義指令 (Custom Directive)1.5 原生 maxlength 屬性結合 Vue2. 特殊場景處理2.1 處理粘貼操作2…

榮耀手機無法連接win11電腦,錯誤消息:“無法在此設備上加載驅動程序 (hn_usbccgpfilter.sys)。”解決方案

錯誤發生背景&#xff1a; 本人于2024年月底買了一部榮耀Magic7 RSR手機&#xff0c;當時在win10的rog電腦上可以正常連接&#xff0c;但是后面換了一個acer的win11電腦后&#xff0c;一開始可以正常連接&#xff0c;但是要我下載榮耀Hisuite&#xff08;榮耀手機助理&#xff…

springboot env 多環境配置入門與實戰

Spring Boot3 Env 項目地址 https://gitee.com/supervol/loong-springboot-study &#xff08;記得給個start&#xff0c;感謝&#xff09; Env 概述 在 Spring Boot 3 開發中&#xff0c;多環境配置是核心能力之一&#xff0c;其目的是為不同場景&#xff08;如開發、測試、…

利用conda打包/復刻生信環境

01、寫在前面 大家拿到自己的服務器(趁開學| 入手足夠完成碩博生涯的生信環境)后可能需要安裝很多的軟件與包&#xff0c;Linux中許多包的安裝依賴過多、安裝復雜。而conda作為一個能夠直接安裝超過90%軟件的"管家"&#xff0c;能夠像Windows和手機中的應用商店那樣…

數據分析:合并

&#x1f537; DA37&#xff1a;統計運動會項目報名人數&#xff08;僅輸出有人報名的項目&#xff09;? 題目描述給定兩個 CSV 文件&#xff1a;items.csv&#xff1a;包含項目信息&#xff08;item_id, item_name, location&#xff09;signup.csv&#xff1a;包含員工報名信…

高并發內存池(一):項目介紹和ThreadCache(線程緩存)實現

前言&#xff1a;本文將要介紹的高并發內存池&#xff0c;它的原型是Google的?個開源項?tcmalloc&#xff0c;全稱Thread-Caching Malloc&#xff0c;近一個月我將以學習為目的來模擬實現一個精簡版的高并發內存池&#xff0c;并對核心技術分塊進行精細剖析&#xff0c;分享在…

RK3399平臺ffmpeg-VPU硬編碼錄制USB攝像頭視頻、H264或MJPEG編碼

文章目錄 1 前言2 項目內容詳細說明2.0 功能2.1 工程文件夾說明 3 代碼3.1 CameraThread類3.1 CameraThreadImpl類 4 資源下載 1 前言 在某項目中需要在RK3399平臺實現USB攝像頭畫面的實時預覽、視頻錄制、拍照存儲等功能。 ??先來看需要實現的最終效果。 ?? ffmpeg USB攝…

解決藍牙耳機連win11電腦畫質依托答辯問題

以wh910n藍牙耳機為例 設置-系統-聲音-輸出&#xff08;耳機&#xff09;-常規&#xff08;輸出點不允許&#xff09;然后刪除wh910n藍牙設備 重新配對藍牙耳機

獨立顯卡和集成顯卡切換電腦卡住了怎么辦?

你是不是也遇到過這種情況——正忙著切換顯卡呢&#xff0c;電腦突然就卡住了&#xff0c;鼠標不動、屏幕定格&#xff0c;怎么按都沒反應&#xff1f;其實這種問題挺常見的&#xff0c;尤其是用了雙顯卡的筆記本或者工作站。別急著強制關機&#xff0c;嗯&#xff0c;咱們一步…

Java根據模版導出PDF文件

問題 工作中經常有這樣的需求&#xff0c;將一些數據&#xff0c;導出為下圖的PDF文件&#xff0c;那Java怎么做呢&#xff1f;今天手把手教你 準備模版 模版地址&#xff1a;https://download.csdn.net/download/ZHUSHANGLIN/91923381 修改模版使用AcrobatProPortable工具…

力扣hot100:環形鏈表(快慢指針法)(141)

一、題目描述二、思路分析這是鏈表題目中的經典問題&#xff0c;核心就是 如何判斷鏈表是否有環。 常見的兩種方法有&#xff1a;哈希表法&#xff1a;用一個集合存儲訪問過的節點&#xff0c;如果再次遇到相同節點說明有環。缺點&#xff1a;需要額外的空間&#xff0c;空間復…

AI 智能編碼工具:重塑開發效率的革命,從 GitHub Copilot 到國產新秀的全面解析

目錄 引言 一、主流智能編碼工具深度測評&#xff1a;從功能到實戰 1. GitHub Copilot&#xff1a;AI 編碼的 “開山鼻祖” 核心特性與實戰代碼 優缺點總結 2. Baidu Comate&#xff1a;文心大模型加持的 “國產之光” 核心特性與實戰代碼 優缺點總結 3. 通義靈碼&…

Server 13 ,CentOS 上使用 Nginx 部署多個前端項目完整指南( 支持多端口與腳本自動化 )

目錄 前言 一、實際背景 1.1 并行部署 1.2 接口代理 1.3 刷新問題 二、安裝腳本 2.1 創建腳本 2.2 不同系統 2.3 執行完成 三、配置文件 3.1 配置文件 3.2 目錄結構 3.3 重新啟動 四、驗證訪問 五、問題排查 5.1 訪問 404 5.2 接口 502 六、本文總結 6.1 清理…

2025最新:徹底解決Docker拉取鏡像超時問題

文章目錄&#x1f433; 解決 Docker 拉取鏡像超時&#xff1a;context deadline exceeded 完整指南&#xff08;2025 親測有效&#xff09;&#x1f525; 問題描述&#x1f9e9; 根本原因分析? 解決方案匯總? 方案 1&#xff1a;配置多源鏡像加速器&#xff08;推薦&#xff…

小鵬汽車 vla 算法最新進展和模型結構細節

小鵬汽車在 VLA&#xff08;視覺 - 語言 - 動作&#xff09;算法領域的最新進展和模型結構細節&#xff0c;體現了其在端到端智駕系統和車端大模型部署上的技術突破。以下是基于 2025 年 9 月最新公開信息的深度解析&#xff1a; 一、最新進展&#xff1a;全場景 VLA 系統量產落…

斐波那契數列推廣

目錄 問題&#xff1a; 法一&#xff1a; 法二&#xff1a; 例題: 問題&#xff1a; 已知斐波那契數列的第一個和最后一個數字&#xff0c;如何求整個數列&#xff08;即第二個數字&#xff09; 法一&#xff1a; 主要是將數列拆分成兩個數列的思想 法二&#xff1a; 暴力…