feat: 实现文件上传功能并完善测试覆盖

- 新增 upload.rs 模块,支持 multipart/form-data 文件上传
- 文件按日期存储在 storage/YYYY-MM-DD/ 目录下
- 使用 UUID 生成唯一文件名,保留原始扩展名
- 添加 axum-extra, uuid, chrono 依赖

新增测试用例:
- config_test.rs: 6 个测试 (配置结构验证)
- router_test.rs: 11 个测试 (路由匹配逻辑)
- handler_test.rs: 8 个测试 (请求处理)
- upload_test.rs: 13 个测试 (文件上传功能)

其他改进:
- 优化 handler.rs 代码注释
- 更新 .gitignore 忽略 storage/ 和 .claude/
- 添加 CLAUDE.md 项目指南文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 22:11:42 +08:00
parent 5f3269bad5
commit ab368ead1b
14 changed files with 2113 additions and 15 deletions

View File

@@ -1,10 +1,11 @@
use std::net::SocketAddr;
use std::path::Path;
use std::sync::Arc;
use axum::{routing::any, Router};
use axum::{routing::{any, post}, Router};
use mock_server::loader::MockLoader;
use mock_server::router::MockRouter;
use mock_server::handler::{mock_handler, AppState};
use mock_server::upload::upload_handler;
#[tokio::main]
async fn main() {
@@ -22,21 +23,31 @@ async fn main() {
println!("Scanning mocks directory...");
let index = MockLoader::load_all_from_dir(mocks_dir);
// 3. 构建路由引擎并包装为共享状态
// 3. 确保 storage 目录存在
let storage_dir = Path::new("./storage");
if !storage_dir.exists() {
println!("Creating storage directory...");
std::fs::create_dir_all(storage_dir).unwrap();
}
// 4. 构建路由引擎并包装为共享状态
let router_engine = MockRouter::new(index);
let shared_state = Arc::new(AppState {
router: router_engine,
});
// 4. 配置 Axum 路由
// 使用 any(mock_handler) 意味着它会接管所有 HTTP 方法和所有路径的请求
// 5. 配置 Axum 路由
// 文件上传路由POST /api/upload
// 其他所有请求由 mock_handler 处理
let app = Router::new()
.route("/api/upload", post(upload_handler))
.fallback(any(mock_handler))
.with_state(shared_state);
// 5. 启动服务
// 6. 启动服务
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
println!("🚀 Rust Mock Server is running on http://{}", addr);
println!("📁 File upload endpoint: POST http://{}/api/upload", addr);
println!("Ready to handle requests based on your YAML definitions.");
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();