Rust新手练习案例库- rust-learning-example

rust-learning-example 是一个Rust开发练习案例库,一个分支为一篇案例分享内容和实战代码。它适合Rust入门练习,后序会陆续更新练习分支。

Github地址: https://github.com/zsf2025/rust-learning-example/tree/feat-axum

下面我们来看看第一个练习案例:《Axum入门实战练习》

一、入门级:夯实基础(重点练核心 API)

适合刚接触 Axum,先熟悉「路由定义、请求解析、响应返回」的基础用法。

1. 多功能 Hello World(覆盖基础请求处理)

目标:不只是简单返回字符串,而是结合路径参数、查询参数、JSON 请求/响应。

  • 核心功能:
    • 固定路由:GET / 返回 "Hello Axum!"
    • 路径参数:GET /hello/:name 返回 "Hello, {name}!"(解析路径参数)
    • 查询参数:GET /greet?name=Alice&age=20 返回 "Greet Alice (20)!"(解析 Query
    • JSON 请求:POST /echo 接收 JSON 数据(如 { "msg": "hi" }),原样返回(用 Json 提取器)
  • 依赖:axum + tokio + serde(derive/_json)
  • 练习点:Router 路由组合、Path/Query/Json 提取器、IntoResponse 响应 trait。
2. 静态文件服务器

目标 :学会用 Axum 提供静态资源(如 HTML、CSS、图片),熟悉 ServeDir 服务。

  • 核心功能:
    • 访问 GET / 返回 static/index.html(前端静态页面)
    • 访问 GET /assets/:file 读取 static/assets/ 下的文件(图片、CSS)
    • 404 页面:访问不存在的路由返回自定义 404 HTML
  • 依赖:axum + tokio + tower-http(ServeDir)
  • 练习点:Router::nest 路由嵌套、ServeDir 静态资源服务、自定义错误响应。

这里假设你已经入门基本语法,并且安装了rust和cargo, 现在出发学习案例:

1. 多功能 Hello World(覆盖基础请求处理)

初始化项目 + 依赖添加说明

这里我们需要添加axumweb框架、tokio异步运行时依赖(它相当于异步版本的std::thread

复制代码
cargo new rust-learning-example

cd rust-learning-example

# 添加 axum(默认包含核心功能)
cargo add axum

# 添加 tokio(需启用多线程运行时、宏、网络功能)
cargo add tokio --features rt-multi-thread,macros,net

# 可选:添加 serde(用于 JSON 序列化/反序列化,Web 开发必备)
cargo add serde --features derive
最终Cargo.tomal依赖会自动生成如下(无需手动修改):
复制代码
[dependencies]
axum = "0.8.8"
serde = { version = "1.0.228", features = ["derive"] }
tokio = { version = "1.49.0", features = ["rt-multi-thread", "macros", "net"] }

🚀 准备就绪,现在开始我们的第一Axum程序。

1.1 启动Axum Web服务, 练习【固定路由】GET /

rust 复制代码
// 以下为 main.rs 文件内容

use axum::{routing::get, Router, serve };
use tokio::net::TcpListener;

// 返回 &'static str(静态字符串,Axum 自动转为 200 OK 响应)
async fn hello_world() -> &'static str {
    "Hello, Axum! 🚀"
}

#[tokio::main]
    // 给 main 加返回值:Result<(), 错误类型>
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建路由器(Router):管理路由规则
    let app = Router::new()
    // 绑定路由:GET 方法 + 路径 "/" + 处理函数 hello_world
    .route("/", get(hello_world));
    // 绑定端口(返回 Result,需用 ? 处理错误)
    let listener = TcpListener::bind("127.0.0.1:3000").await?;
    println!("服务器启动成功!访问:http://127.0.0.1:3000");
    // 启动服务器
    serve(listener, app.into_make_service()).await?;
    // 返回
    Ok(())
}

👋 用浏览器访问http://127.0.0.1:3000, 我可以看到页面输出Hello, Axum! 🚀

1.2 练习【解析路径参数】 GET /hello/:name(基于之前的代码...为省略部分)

rust 复制代码
// 依赖引入Path,用来解析路径
use axum::{routing::get, Router, serve, extract::{ Path } };
....

// 实现一个hello_name函数
async fn hello_name(Path(name): Path<String>) -> String {
    format!("Hello, {}! 👋", name)
}
...
// let = Router::new()后面添加
.route("/hello/{name}", get(hello_name))
...

👋在浏览器输入http://127.0.0.1:3000/hello/zhang心独酌,可以看到页面输出Hello, zhang心独酌! 👋

1.3 练习【查询参数】GET /greet?name=Alice&age=20

rust 复制代码
// 依赖引入Query
use axum::{routing::get, Router, serve, extract::{ Path, Query } };

...
// 实现greet函数
// Query是一个Map,所有在rust中我们使用HashMap来接收
async fn greet(params: Query<std::collections::HashMap<String, String>>) -> String {
    // 处理两个参数都有,通过元组匹配
    if let (Some(name), Some(sex)) = (params.get("name"), params.get("sex")) {
        format!("Greetings, {} the {}! 🌟", name, sex)
    }
    // 处理只有name
    else if let Some(name) = params.get("name") {
        format!("Greetings, {}! 🌟", name)
    } 
    // 处理只有sex
    else if let Some(sex) = params.get("sex") {
        format!("Greetings, {}! 🌟", sex)
    }
    // 处理没有参数
    else {
        "Greetings, stranger! 🌟".to_string()
    }
}
...
// let = Router::new()后面添加
.route("/greet", get(greet))
...

👋在浏览器输入http://127.0.0.1:3000/greet?name=zhang心独酌&sex=男,可以看到页面输出Greetings, zhang心独酌 the 男! 🌟。其他每种分支都可以测试以下。

1.4 练习【JSON请求】POST /echo 接收 JSON 数据(如 { "msg": "hi" }),原样返回(用 Json 提取器)

rust 复制代码
/**
 * routing添加post,用来post请求
 * extract添加Json, 可以理解解析请求体json/响应json包装器
 * http::StatusCode 就是请求的http状态码,OK代表200,其他可以查阅文档
 * response::IntoResponse 一个trait, 自动转换成HTTP响应并发送给客户端
 */
use axum::{routing::{ get, post }, Router, serve, extract::{ Path, Query, Json }, http::StatusCode, response::IntoResponse };
....
/**
 * Deserialize 反序列化,从请求把JSON解析为结果体
 * Serialize 序列化
 */
use serde::{Deserialize, Serialize};
....
// 实现一个结构体
#[derive(Deserialize, Serialize)]
struct Payload {
    msg: String,
}
....
// 实现路由处理函数
async fn echo_json(Json(payload): Json<Payload>) -> impl IntoResponse {
    (StatusCode::OK, Json(Payload {
        msg: format!("Echo: {}", payload.msg),
    }))
}
...
.route("/echo", post(echo_json))
...

👋我们可以用postman测试一下,header设置Content-type:application/json,Body填写JSON{"msg": "zhang心独酌"},结果返回:

json 复制代码
  {
      "msg": "Echo: zhang心独酌"
  }
👋👋到这我们已经完成了实战1【基础请求处理】练习,从中我们学会了怎么解析路径参数、怎么读取query参数、body的json参数。避免篇幅太长,实战2【静态文件服务器】我们放在feat-axum-入门级-实战2中进行练习。

🤔留给自己的课后作业

  1. 以下数据类型解析:

    • form-data
    • x-wwww-form-urlencoded
    • Binary
    • 等其他一些类型
  2. 混合解析练习:body+query+路径解析

相关推荐
Chester_19994 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
2601_962055975 小时前
跟据spring boot版本,查看对应的tomcat,并查看可支持的tomcat的版本范围
spring boot·后端·tomcat
EXI-小洲5 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
会周易的程序员5 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
机器视觉知识推荐、就业指导5 小时前
为什么老说“纯 Qt 没啥就业市场”?
开发语言·qt
telepan5 小时前
Qt 开发避坑与性能指南:如何优雅、安全地定义全局常量字符串?
开发语言·qt
m0_695251496 小时前
Qt MaintenanceTool 使用国内镜像加速下载(超详细教程)
开发语言·qt
Lost of 程序猿6 小时前
ASP.NET Core API 幂等性设计深度实战:从一次重复申领事故说起
后端·asp.net
q平面人6 小时前
【总工笔记】mindoc平板、桌面端笔记软件,发布到mindoc服务端
rust·tauri·华为平板·mindoc·总工笔记
大衛說7 小时前
《Python 从入门到精通》系列总览与学习路线
开发语言·python·学习