这是一个基于Rust Axum框架的生产级Web应用程序示例,展示了如何使用Rust构建高性能、安全且可维护的Web服务。
代码已更新至 AXUM 0.7 标签: axum-06-to-07
本仓库包含 Rust Axum 完整课程的源代码,课程可在 YouTube 上观看。代码采用 MIT 或 Apache 许可证,可免费使用。
完整的 Rust Web 应用生产蓝图课程和仓库位于 https://rust10x.com/web-app(YouTube 视频:第01集 - Rust Web 应用 - 从课程到生产编程)
重要提示:请确保刷新此仓库。我为 AUTH_TOKEN 的 cookie.add 实现了一个修复(详见下方注释部分)。
这里有一个由 @FloWi 制作的按章节分叉版本。非常感谢!
- Web框架: Axum - 基于Tokio的高性能Web框架
- 异步运行时: Tokio - Rust的异步运行时
- 数据库: PostgreSQL - 强大的关系型数据库
- 数据库访问: SQLx - 异步SQL工具库
- 认证: 基于Cookie的自定义认证系统
- 日志: tracing - 用于分布式追踪的日志库
- 序列化/反序列化: serde - 高效的数据序列化框架
src/
├── _dev_utils/ # 开发工具和辅助函数
├── model/ # 数据模型和业务逻辑
│ ├── error.rs # 模型层错误处理
│ ├── store.rs # 数据库连接管理
│ ├── task.rs # 任务模型
│ └── ticket.rs # 票据模型
├── web/ # Web层和HTTP处理
│ ├── mw_auth.rs # 认证中间件
│ ├── routes_login.rs # 登录路由
│ ├── routes_static.rs # 静态文件路由
│ └── routes_tickets.rs # 票据API路由
├── config.rs # 应用配置
├── ctx.rs # 请求上下文
├── error.rs # 应用错误处理
├── log.rs # 日志功能
├── main.rs # 应用入口点
├── model.rs # 模型层入口
└── web.rs # Web层入口
# 启动 postgresql 服务器 docker 镜像:
docker run --rm --name pg -p 5432:5432 \
-e POSTGRES_PASSWORD=welcome \
postgres:17
# (可选)在 pg 上启动 psql 终端。
# 在另一个终端(标签页)中运行 psql:
docker exec -it -u postgres pg psql
# (可选)让 pg 打印所有 sql 语句。
# 在上面启动的 psql 命令行中执行。
ALTER DATABASE postgres SET log_statement = 'all';# 终端 1 - 运行服务器。
cargo watch -q -c -w src/ -x "run"
# 终端 2 - 运行测试。
cargo watch -q -c -w examples/ -x "run --example quick_dev"RUST_LOG=info cargo watch -q -c -w src/ -x "run"cargo watch -q -c -w examples/ -x "run --example quick_dev"# 终端 1 - 运行服务器。
cargo run
# 终端 2 - 运行测试。
cargo test quick_dev -- --nocapture注意:使用
cargo install cargo-watch安装 cargo watch。
# 终端 1 - 运行服务器。
cargo watch -q -c -w crates/services/web-server/src/ -w crates/libs/ -w .cargo/ -x "run -p web-server"
# 终端 2 - 运行 quick_dev。
cargo watch -q -c -w crates/services/web-server/examples/ -x "run -p web-server --example quick_dev"# 终端 1 - 运行服务器。
cargo run -p web-server
# 终端 2 - 运行测试。
cargo run -p web-server --example quick_devcargo watch -q -c -x "test -- --nocapture"
# 使用过滤器的特定测试。
cargo watch -q -c -x "test -p lib-core test_create -- --nocapture"
# 测试task.rs中所有测试函数
cargo watch -q -c -x "test model::task::tests -- --nocapture"
cargo test -- --nocapture
cargo watch -q -c -x "test -p lib-core model::task::tests::test_create -- --nocapture"| 端点 | 方法 | 描述 | 认证要求 |
|---|---|---|---|
/api/login |
POST | 用户登录 | 否 |
/api/tickets |
GET | 获取所有票据 | 是 |
/api/tickets |
POST | 创建新票据 | 是 |
/api/tickets/:id |
DELETE | 删除指定票据 | 是 |
本项目采用分层架构设计:
-
Web层:处理HTTP请求和响应,负责路由、中间件和请求/响应序列化
- 认证(Authentication):验证用户身份
- 请求解析:将HTTP请求转换为应用可处理的数据
- 响应构建:将应用数据转换为HTTP响应
-
模型层:包含业务逻辑和数据访问
- 授权(Authorization):检查用户权限
- 业务规则:实现应用的核心功能
- 数据访问:与数据库交互
-
上下文(Context):连接Web层和模型层
- 用户身份:保存已认证用户的信息
- 请求范围:在请求生命周期内共享数据
这种设计允许模型层独立于Web框架运行,便于在不同类型的服务中重用业务逻辑。
# 测试 : async fn test_create_ok() -> Result<()>
cargo watch -q -c -x "test test_create_ok -- --nocapture"cargo run -p gen-key- 重要 - 对于
AUTH_TOKENcookie,请确保调用cookie.set_path("/");。参见提交 - 修复 AUTH_TOKEN cookie 问题 tests/quick_dev.rs文件已移动到examples/quick_dev.rs(代码相同),因为这样更合适,并且似乎解决了在 Windows 上同时运行test和run的限制。- 在我的 Fedora Linux 环境中,对于 cargo watch(最新版本 8.4.0)需要使用
--poll标志 - 服务器和测试都需要。 没有它就不会更新。参见 #1 - 确保使用
axum版本0.6.16或更高版本,因为版本0.6.15在静态路由方面有一个错误。 - 这里有一个由 @FloWi 制作的按章节分叉版本。非常感谢!
此仓库可在 GitHub 上找到。
flowchart TD
A[程序入口 main.rs] --> B[初始化日志 tracing_subscriber]
B --> C[初始化开发环境 _dev_utils::init_dev]
C --> D[创建 ModelManager]
D --> E[加载配置 config.rs]
E --> F[创建数据库连接池 model/store.rs]
F --> G[定义API路由 routes_tickets.rs]
G --> H[定义公共路由 routes_hello.rs]
H --> I[合并API和公共路由]
I --> J[添加认证中间件 mw_auth.rs]
J --> K[添加Cookie管理层]
K --> L[添加静态文件服务]
L --> M[启动HTTP服务器]
flowchart TD
A[HTTP请求] --> B[路由匹配]
B --> C{是否需要认证?}
C -->|是| D[认证中间件 mw_auth.rs]
C -->|否| E[公共路由处理]
D --> F{认证成功?}
F -->|是| G[创建请求上下文 Ctx]
F -->|否| H[返回401错误]
G --> I[路由处理函数]
E --> I
I --> J[调用模型层 model/*.rs]
J --> K[数据库操作 sqlx]
K --> L[构建响应]
L --> M[错误处理 error.rs]
M --> N[日志记录 log.rs]
N --> O[HTTP响应]
flowchart TD
A[main.rs] --> B[config.rs]
A --> C[model.rs]
A --> D[web.rs]
A --> E[_dev_utils.rs]
A --> F[error.rs]
A --> G[log.rs]
A --> H[ctx.rs]
C --> C1[model/store.rs]
C --> C2[model/ticket.rs]
D --> D1[web/mw_auth.rs]
D --> D2[web/routes_login.rs]
D --> D3[web/routes_tickets.rs]
E --> E1[_dev_utils/dev_db.rs]
flowchart TD
A[程序启动] --> B[config.rs::config]
B --> C[config.rs::load_from_env]
C --> D[config.rs::get_env]
D --> E{环境变量存在?}
E -->|是| F[返回环境变量值]
E -->|否| G[返回错误 ConfigMissingEnv]
flowchart TD
A[_dev_utils::init_dev] --> B[dev_db::init_dev_db]
B --> C[创建postgres数据库]
C --> D[执行SQL初始化脚本]
D --> E[返回数据库连接池]
flowchart TD
A[用户登录请求] --> B[routes_login.rs::api_login_handler]
B --> C[验证用户凭据]
C --> D[创建认证令牌]
D --> E[设置AUTH_TOKEN cookie]
E --> F[返回登录成功响应]
G[受保护API请求] --> H[mw_auth.rs::mw_require_auth]
H --> I[mw_auth.rs::mw_ctx_resolver]
I --> J{AUTH_TOKEN cookie存在?}
J -->|是| K[解析用户ID]
J -->|否| L[返回401错误]
K --> M[创建请求上下文 Ctx]
M --> N[继续处理请求]