use axum::{ body::Body, extract::{Query, State}, http::{HeaderMap, Method, Request, StatusCode}, response::{IntoResponse, Response}, }; use std::collections::HashMap; use std::sync::{Arc, RwLock}; use tokio_util::io::ReaderStream; use crate::router::MockRouter; /// 共享的应用状态,router 由 RwLock 保护以支持热重载 pub struct AppState { pub router: RwLock, } /// 全局统一请求处理函数 pub async fn mock_handler( State(state): State>, method: Method, headers: HeaderMap, Query(params): Query>, req: Request, ) -> impl IntoResponse { let path = req.uri().path().to_string(); let method_str = method.as_str().to_string(); // 1. 将需要的数据克隆出来,断开与 req 的借用关系 let body_bytes = match axum::body::to_bytes(req.into_body(), 10 * 1024 * 1024).await { Ok(bytes) => bytes, Err(_) => { return Response::builder() .status(StatusCode::BAD_REQUEST) .body(Body::from("Read body error")) .unwrap(); } }; let incoming_json: Option = serde_json::from_slice(&body_bytes).ok(); // 2. 将 Axum HeaderMap 转换为简单的 HashMap let mut req_headers = HashMap::new(); for (name, value) in headers.iter() { if let Ok(v) = value.to_str() { req_headers.insert(name.as_str().to_string(), v.to_string()); } } // 3. 执行匹配逻辑:先获取读锁 (Read Lock) let maybe_rule = { let router = state.router.read().expect("Failed to acquire read lock"); router.match_rule(&method_str, &path, ¶ms, &req_headers, &incoming_json).cloned() // 使用 .cloned() 以便尽早释放读锁,避免阻塞热重载写锁 }; if let Some(rule) = maybe_rule { // 4. 处理模拟延迟 if let Some(ref settings) = rule.settings { if let Some(delay) = settings.delay_ms { tokio::time::sleep(std::time::Duration::from_millis(delay)).await; } } // 5. 构建响应 let status = StatusCode::from_u16(rule.response.status).unwrap_or(StatusCode::OK); let mut response_builder = Response::builder().status(status); if let Some(ref h) = rule.response.headers { for (k, v) in h { response_builder = response_builder.header(k, v); } } // 6. Smart Body 逻辑 if let Some(file_path) = rule.response.get_file_path() { match tokio::fs::File::open(file_path).await { Ok(file) => { let stream = ReaderStream::new(file); let body = Body::from_stream(stream); response_builder.body(body).unwrap() } Err(_) => Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) .body(Body::from(format!( "Mock Error: File not found at {}", file_path ))) .unwrap(), } } else { // 内联模式:直接返回字符串内容 response_builder .body(Body::from(rule.response.body.clone())) .unwrap() } } else { println!("请求头{:?}", req_headers); // 匹配失败返回 404 Response::builder() .status(StatusCode::NOT_FOUND) .body(Body::from("No mock rule matched this request")) .unwrap() } }