Web 与生态
axum/actix、serde、sqlx、reqwest。
Web 与生态
这一课你将能做到
- 用 axum 搭起 HTTP 服务:路由、提取器、共享状态三件套
- 用 serde 完成 JSON 的编解码,理解它对比 Jackson 的性能来源
- 认清 Rust Web 生态的全景图,知道每个领域该用什么 crate
为什么要学
Java Web 你熟的是 Spring Boot:注解扫描、反射调用、内嵌 Tomcat。Rust 的 axum 是另一条路:函数即 handler、路由显式注册、无反射——启动是毫秒级,内存是个位数 MB,QPS 上限高一个量级。判题系统这种「高频提交 + 低延迟查询」的服务,正是这类框架的价值区。
这一课把前面所有知识串起来:enum 建模状态(第 5 课)、Result 错误处理(第 6 课)、trait 约束(第 7 课)、Arc/Mutex 共享状态(第 9 课)、derive 宏(第 10 课)——全部落到一个能跑的接口服务上。
先建立图像
Spring Boot axum
@RestController + @GetMapping ↔ Router::new().route("/x", get(handler))
@RequestBody DTO ↔ Json<SubmitReq> 提取器
@Service @Autowired ↔ State<AppState>(编译期注入,无反射)
Jackson ObjectMapper ↔ serde_json(编译期生成编解码器)
内嵌 Tomcat(线程池) ↔ hyper + tokio(async,事件驱动)
跟着做
步骤 1:建项目与依赖
cargo new judge-api
cd judge-api
Cargo.toml:
[package]
name = "judge-api"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
四个依赖各司其职:axum 是 Web 框架,tokio 是它脚下的 async 运行时,serde 负责序列化,serde_json 是 JSON 后端。
步骤 2:数据模型——derive 一把梭
use serde::{Deserialize, Serialize};
#[derive(Serialize, Clone, Debug)]
struct Submission {
id: u64,
language: String,
status: String, // PENDING / RUNNING / AC / WA
}
#[derive(Deserialize)]
struct SubmitReq {
language: String,
code: String,
}
请求体 SubmitReq 只需 Deserialize,响应体 Submission 只需 Serialize——按需 derive,编解码器编译期生成。
步骤 3:共享状态与服务骨架
use axum::{
extract::{Path, State},
http::StatusCode,
routing::{get, post},
Json, Router,
};
use std::{collections::HashMap, sync::{Arc, Mutex}};
#[derive(Clone, Default)]
struct AppState {
store: Arc<Mutex<HashMap<u64, Submission>>>, // 真实系统换成数据库
}
#[tokio::main]
async fn main() {
let state = AppState::default();
let app = Router::new()
.route("/submissions", post(submit)) // 提交判题
.route("/submissions/:id", get(query)) // 查询结果
.with_state(state); // 状态注入所有 handler
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
println!("listening on http://localhost:3000");
axum::serve(listener, app).await.unwrap();
}