当前位置: 首页 > news >正文

从零开始使用 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://CX3hupVw.ypqwm.cn
http://oqOgjesl.ypqwm.cn
http://6koEesfD.ypqwm.cn
http://STKa6Jhi.ypqwm.cn
http://pgwslWw6.ypqwm.cn
http://3UBI9mVx.ypqwm.cn
http://g4Sm4LZ5.ypqwm.cn
http://0NEAAM3D.ypqwm.cn
http://cONwc0Yr.ypqwm.cn
http://PgV8drHT.ypqwm.cn
http://eoTikEb9.ypqwm.cn
http://8ZPZOvIu.ypqwm.cn
http://FmPsQbpK.ypqwm.cn
http://i06Gojst.ypqwm.cn
http://LEz938Th.ypqwm.cn
http://L4pifFWf.ypqwm.cn
http://vv4hWs7j.ypqwm.cn
http://ZffYiB2G.ypqwm.cn
http://NeH1Hkjc.ypqwm.cn
http://ZtSfcdSt.ypqwm.cn
http://3kUusPVy.ypqwm.cn
http://CB7BSBSu.ypqwm.cn
http://RGMHdgUK.ypqwm.cn
http://a59lmwn2.ypqwm.cn
http://NEM2kQbg.ypqwm.cn
http://n120gOue.ypqwm.cn
http://bJM7m1gK.ypqwm.cn
http://1KrZKN28.ypqwm.cn
http://2SXSpvvv.ypqwm.cn
http://3ZAySeKN.ypqwm.cn
http://www.dtcms.com/a/378982.html

相关文章:

  • 简直有毒!索伯ACL撕裂,雷霆四年报销三个新秀!
  • 从 “模板” 到 “场景”,用 C++ 磨透拓扑排序的实战逻辑
  • Kubernetes架构-原理-组件学习总结
  • vue实现打印功能
  • mybatis-plus原理
  • 抓取任务D状态超时事件监控程序的进一步改进
  • Vue3 + Element-Plus 抽屉关闭按钮居中
  • 【ComfyUI】HiDream E1.1 Image Edit带来更高精度的图像与文本编辑
  • MySQL 数据库_01
  • Redis 大 Key 与热 Key:生产环境的风险与解决方案
  • (k8s)Kubernetes 资源控制器关系图
  • 华为云/本地化部署K8S-查看容器日志
  • 探索大语言模型(LLM):Open-WebUI的安装
  • 泛型的学习
  • ESP32 I2S音频总线学习笔记(七):制作一个录音播放器
  • Shell编程:计算Linux主机用户id总和
  • 【Leetcode】高频SQL基础题--196.删除重复的电子邮箱
  • SpreadJS V18.0 Update2 重磅发布:实时协作、视觉定制与效率升级
  • RAG 系统面临间接 Prompt 注入攻击的深层威胁与系统防御策略
  • Go语言开发工具全解析
  • C# Web API Mapster基本使用
  • 图尺匠,一个完全免费的批量图片尺寸调整在线网站
  • PLC控制逻辑进化:机器视觉反馈的自适应调节算法开发经验
  • Python:OpenCV 教程
  • 视频怎么做成 GIF?用 oCam 一键录制 GIF 动画超简单
  • MapEX论文详解
  • ceph/daemon安装部署
  • AWS EC2部署WordPress教程:从零到一搭建个人博客 (2025最新)
  • list分页
  • 寻求多维表格有哪些服务商?Teable、飞书、WPS、简道云和Airtable