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; 暴力…