Files
udmin/docs/ROUTES.md
ayou a3f2f99a68 docs: 添加项目文档包括总览、架构、流程引擎和服务层
新增以下文档文件:
- PROJECT_OVERVIEW.md 项目总览文档
- BACKEND_ARCHITECTURE.md 后端架构文档
- FRONTEND_ARCHITECTURE.md 前端架构文档
- FLOW_ENGINE.md 流程引擎文档
- SERVICES.md 服务层文档
- ERROR_HANDLING.md 错误处理模块文档

文档内容涵盖项目整体介绍、技术架构、核心模块设计和实现细节
2025-09-24 20:21:45 +08:00

1201 lines
31 KiB
Markdown

# 路由层文档
## 概述
路由层是 UdminAI 的 HTTP API 接口层,负责处理客户端请求、参数验证、权限检查、调用服务层业务逻辑,并返回统一格式的响应。基于 Axum 框架构建,提供 RESTful API 接口。
## 架构设计
### 路由模块结构
```
routes/
├── mod.rs # 路由模块导出和总路由配置
├── auth.rs # 认证相关路由
├── user.rs # 用户管理路由
├── role.rs # 角色管理路由
├── permission.rs # 权限管理路由
├── flow.rs # 流程管理路由
├── schedule_job.rs # 定时任务路由
├── system.rs # 系统管理路由
├── log.rs # 日志查询路由
├── notification.rs # 通知管理路由
└── websocket.rs # WebSocket 路由
```
### 设计原则
- **RESTful 设计**: 遵循 REST API 设计规范
- **统一响应格式**: 所有接口返回统一的响应格式
- **参数验证**: 在路由层进行请求参数验证
- **权限控制**: 集成权限中间件进行访问控制
- **错误处理**: 统一的错误处理和响应
- **文档支持**: 支持 OpenAPI/Swagger 文档生成
## 总路由配置 (mod.rs)
### 路由树结构
```rust
pub fn create_routes() -> Router {
Router::new()
// 认证路由 (无需认证)
.nest("/auth", auth::routes())
// API 路由 (需要认证)
.nest("/api",
Router::new()
.nest("/users", user::routes())
.nest("/roles", role::routes())
.nest("/permissions", permission::routes())
.nest("/flows", flow::routes())
.nest("/jobs", schedule_job::routes())
.nest("/system", system::routes())
.nest("/logs", log::routes())
.nest("/notifications", notification::routes())
.layer(AuthMiddleware::new())
)
// WebSocket 路由
.nest("/ws", websocket::routes())
// 静态文件路由
.nest("/static", static_files::routes())
// 健康检查
.route("/health", get(health_check))
// 中间件层
.layer(CorsLayer::permissive())
.layer(TraceLayer::new_for_http())
.layer(CompressionLayer::new())
}
```
### 中间件配置
```rust
/// 应用中间件
pub fn apply_middlewares(app: Router) -> Router {
app
// 请求追踪
.layer(TraceLayer::new_for_http())
// CORS 支持
.layer(CorsLayer::new()
.allow_origin(Any)
.allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
.allow_headers([AUTHORIZATION, CONTENT_TYPE])
)
// 请求压缩
.layer(CompressionLayer::new())
// 请求限流
.layer(RateLimitLayer::new(100, Duration::from_secs(60)))
// 请求日志
.layer(RequestLogLayer::new())
}
```
## 认证路由 (auth.rs)
### 路由定义
```rust
pub fn routes() -> Router {
Router::new()
.route("/login", post(login))
.route("/logout", post(logout))
.route("/refresh", post(refresh_token))
.route("/register", post(register))
.route("/forgot-password", post(forgot_password))
.route("/reset-password", post(reset_password))
.route("/verify-email", post(verify_email))
}
```
### 接口实现
#### 用户登录
```rust
/// POST /auth/login
/// 用户登录接口
pub async fn login(
State(app_state): State<AppState>,
Json(req): Json<LoginReq>,
) -> Result<Json<ApiResponse<LoginResp>>, AppError> {
// 参数验证
req.validate().map_err(|e| AppError::BadRequest(e.to_string()))?;
// 用户认证
let user = user_service::authenticate(
&app_state.db,
&req.username,
&req.password,
).await?;
// 生成 JWT Token
let token = jwt::generate_token(&user.id, &app_state.jwt_secret)?;
let refresh_token = jwt::generate_refresh_token(&user.id, &app_state.jwt_secret)?;
// 记录登录日志
log_service::log_operation(
&app_state.db,
OperationLog {
user_id: user.id.clone(),
operation: "login".to_string(),
resource: "auth".to_string(),
resource_id: None,
details: json!({ "username": req.username }),
ip_address: extract_client_ip(&req),
user_agent: extract_user_agent(&req),
timestamp: now_fixed_offset(),
},
).await?;
Ok(Json(ApiResponse::success(LoginResp {
user,
token,
refresh_token,
expires_in: 3600,
})))
}
```
#### 请求/响应结构
```rust
#[derive(Debug, Deserialize, Validate)]
pub struct LoginReq {
#[validate(length(min = 3, max = 50))]
pub username: String,
#[validate(length(min = 6))]
pub password: String,
pub remember_me: Option<bool>,
}
#[derive(Debug, Serialize)]
pub struct LoginResp {
pub user: UserDoc,
pub token: String,
pub refresh_token: String,
pub expires_in: u64,
}
```
## 用户管理路由 (user.rs)
### 路由定义
```rust
pub fn routes() -> Router {
Router::new()
.route("/", get(list_users).post(create_user))
.route("/:id", get(get_user).put(update_user).delete(delete_user))
.route("/:id/roles", get(get_user_roles).put(update_user_roles))
.route("/:id/permissions", get(get_user_permissions))
.route("/:id/password", put(change_password))
.route("/:id/status", put(update_user_status))
.route("/profile", get(get_current_user).put(update_profile))
.route("/avatar", post(upload_avatar))
}
```
### 接口实现
#### 用户列表查询
```rust
/// GET /api/users
/// 分页查询用户列表
pub async fn list_users(
State(app_state): State<AppState>,
Query(params): Query<ListUsersQuery>,
Extension(current_user): Extension<CurrentUser>,
) -> Result<Json<ApiResponse<PageResp<UserDoc>>>, AppError> {
// 权限检查
permission_service::check_user_permission(
&app_state.db,
&current_user.id,
"user",
"read",
).await?;
// 构建过滤条件
let filters = UserFilters {
username: params.username,
email: params.email,
status: params.status,
role_ids: params.role_ids,
created_after: params.created_after,
created_before: params.created_before,
};
// 查询用户列表
let result = user_service::list_users(
&app_state.db,
params.page.unwrap_or(1),
params.page_size.unwrap_or(20),
Some(filters),
).await?;
Ok(Json(ApiResponse::success(result)))
}
```
#### 创建用户
```rust
/// POST /api/users
/// 创建新用户
pub async fn create_user(
State(app_state): State<AppState>,
Extension(current_user): Extension<CurrentUser>,
Json(req): Json<CreateUserReq>,
) -> Result<Json<ApiResponse<UserDoc>>, AppError> {
// 参数验证
req.validate().map_err(|e| AppError::BadRequest(e.to_string()))?;
// 权限检查
permission_service::check_user_permission(
&app_state.db,
&current_user.id,
"user",
"create",
).await?;
// 创建用户
let user = user_service::create_user(&app_state.db, req).await?;
// 记录操作日志
log_service::log_operation(
&app_state.db,
OperationLog {
user_id: current_user.id,
operation: "create_user".to_string(),
resource: "user".to_string(),
resource_id: Some(user.id.clone()),
details: json!({ "username": user.username }),
ip_address: None,
user_agent: None,
timestamp: now_fixed_offset(),
},
).await?;
Ok(Json(ApiResponse::success(user)))
}
```
### 查询参数结构
```rust
#[derive(Debug, Deserialize)]
pub struct ListUsersQuery {
pub page: Option<u64>,
pub page_size: Option<u64>,
pub username: Option<String>,
pub email: Option<String>,
pub status: Option<UserStatus>,
pub role_ids: Option<Vec<String>>,
pub created_after: Option<DateTime<FixedOffset>>,
pub created_before: Option<DateTime<FixedOffset>>,
pub sort_by: Option<String>,
pub sort_order: Option<SortOrder>,
}
```
## 流程管理路由 (flow.rs)
### 路由定义
```rust
pub fn routes() -> Router {
Router::new()
.route("/", get(list_flows).post(create_flow))
.route("/:id", get(get_flow).put(update_flow).delete(delete_flow))
.route("/:id/versions", get(list_flow_versions).post(create_flow_version))
.route("/:id/publish", post(publish_flow))
.route("/:id/execute", post(execute_flow))
.route("/:id/executions", get(list_flow_executions))
.route("/executions/:execution_id", get(get_execution_detail))
.route("/executions/:execution_id/stop", post(stop_execution))
.route("/categories", get(list_flow_categories))
.route("/templates", get(list_flow_templates))
}
```
### 接口实现
#### 执行流程
```rust
/// POST /api/flows/:id/execute
/// 执行指定流程
pub async fn execute_flow(
State(app_state): State<AppState>,
Path(flow_id): Path<String>,
Extension(current_user): Extension<CurrentUser>,
Json(req): Json<ExecuteFlowReq>,
) -> Result<Json<ApiResponse<ExecutionResult>>, AppError> {
// 权限检查
permission_service::check_user_permission(
&app_state.db,
&current_user.id,
"flow",
"execute",
).await?;
// 获取流程信息
let flow = flow_service::get_flow_by_id(&app_state.db, &flow_id).await?
.ok_or_else(|| AppError::NotFound("流程不存在".to_string()))?;
// 检查流程状态
if flow.status != FlowStatus::Published {
return Err(AppError::BadRequest("只能执行已发布的流程".to_string()));
}
// 执行选项
let options = ExecuteOptions {
max_steps: req.max_steps,
timeout_ms: req.timeout_ms,
parallel: req.parallel.unwrap_or(false),
stream_events: req.stream_events.unwrap_or(false),
};
// 执行流程
let result = flow_service::execute_flow(
&app_state.db,
&flow_id,
req.input.unwrap_or(json!({})),
options,
).await?;
// 记录执行日志
log_service::log_operation(
&app_state.db,
OperationLog {
user_id: current_user.id,
operation: "execute_flow".to_string(),
resource: "flow".to_string(),
resource_id: Some(flow_id),
details: json!({
"execution_id": result.execution_id,
"status": result.status
}),
ip_address: None,
user_agent: None,
timestamp: now_fixed_offset(),
},
).await?;
Ok(Json(ApiResponse::success(result)))
}
```
#### 请求/响应结构
```rust
#[derive(Debug, Deserialize, Validate)]
pub struct ExecuteFlowReq {
pub input: Option<serde_json::Value>,
pub max_steps: Option<usize>,
pub timeout_ms: Option<u64>,
pub parallel: Option<bool>,
pub stream_events: Option<bool>,
}
#[derive(Debug, Serialize)]
pub struct ExecutionResult {
pub execution_id: String,
pub status: ExecutionStatus,
pub result: Option<serde_json::Value>,
pub error: Option<String>,
pub start_time: DateTime<FixedOffset>,
pub end_time: Option<DateTime<FixedOffset>>,
pub duration_ms: Option<u64>,
}
```
## 定时任务路由 (schedule_job.rs)
### 路由定义
```rust
pub fn routes() -> Router {
Router::new()
.route("/", get(list_jobs).post(create_job))
.route("/:id", get(get_job).put(update_job).delete(delete_job))
.route("/:id/enable", post(enable_job))
.route("/:id/disable", post(disable_job))
.route("/:id/trigger", post(trigger_job))
.route("/:id/executions", get(list_job_executions))
.route("/executions/:execution_id", get(get_execution_detail))
.route("/cron/validate", post(validate_cron))
.route("/cron/next-runs", post(get_next_runs))
}
```
### 接口实现
#### 创建定时任务
```rust
/// POST /api/jobs
/// 创建定时任务
pub async fn create_job(
State(app_state): State<AppState>,
Extension(current_user): Extension<CurrentUser>,
Json(req): Json<CreateScheduleJobReq>,
) -> Result<Json<ApiResponse<ScheduleJobDoc>>, AppError> {
// 参数验证
req.validate().map_err(|e| AppError::BadRequest(e.to_string()))?;
// 权限检查
permission_service::check_user_permission(
&app_state.db,
&current_user.id,
"job",
"create",
).await?;
// 验证 Cron 表达式
cron::Schedule::from_str(&req.cron_expression)
.map_err(|_| AppError::BadRequest("无效的 Cron 表达式".to_string()))?;
// 创建任务
let job = schedule_job_service::create_schedule_job(&app_state.db, req).await?;
// 注册到调度器
if job.enabled {
schedule_job_service::register_job_to_scheduler(
&app_state.scheduler,
&job,
).await?;
}
Ok(Json(ApiResponse::success(job)))
}
```
#### Cron 表达式验证
```rust
/// POST /api/jobs/cron/validate
/// 验证 Cron 表达式
pub async fn validate_cron(
Json(req): Json<ValidateCronReq>,
) -> Result<Json<ApiResponse<ValidateCronResp>>, AppError> {
let schedule = cron::Schedule::from_str(&req.cron_expression)
.map_err(|e| AppError::BadRequest(format!("无效的 Cron 表达式: {}", e)))?;
// 计算接下来的执行时间
let now = Utc::now();
let next_runs: Vec<DateTime<Utc>> = schedule
.upcoming(Utc)
.take(5)
.collect();
Ok(Json(ApiResponse::success(ValidateCronResp {
valid: true,
next_runs,
description: describe_cron(&req.cron_expression),
})))
}
```
## WebSocket 路由 (websocket.rs)
### 路由定义
```rust
pub fn routes() -> Router {
Router::new()
.route("/flow-execution/:execution_id", get(flow_execution_ws))
.route("/system-monitor", get(system_monitor_ws))
.route("/notifications", get(notifications_ws))
.route("/logs", get(logs_ws))
}
```
### WebSocket 处理
#### 流程执行监控
```rust
/// GET /ws/flow-execution/:execution_id
/// 流程执行实时监控
pub async fn flow_execution_ws(
ws: WebSocketUpgrade,
Path(execution_id): Path<String>,
Extension(current_user): Extension<CurrentUser>,
State(app_state): State<AppState>,
) -> Result<Response, AppError> {
// 权限检查
permission_service::check_user_permission(
&app_state.db,
&current_user.id,
"flow",
"read",
).await?;
Ok(ws.on_upgrade(move |socket| {
handle_flow_execution_ws(socket, execution_id, current_user, app_state)
}))
}
async fn handle_flow_execution_ws(
socket: WebSocket,
execution_id: String,
current_user: CurrentUser,
app_state: AppState,
) {
let (mut sender, mut receiver) = socket.split();
// 订阅执行事件
let mut event_stream = app_state.event_bus
.subscribe(&format!("flow_execution:{}", execution_id))
.await;
// 发送事件到客户端
tokio::spawn(async move {
while let Ok(event) = event_stream.recv().await {
let message = serde_json::to_string(&event).unwrap();
if sender.send(Message::Text(message)).await.is_err() {
break;
}
}
});
// 处理客户端消息
while let Some(msg) = receiver.next().await {
match msg {
Ok(Message::Text(text)) => {
// 处理客户端命令
if let Ok(command) = serde_json::from_str::<WsCommand>(&text) {
handle_ws_command(command, &app_state).await;
}
}
Ok(Message::Close(_)) => break,
_ => {}
}
}
}
```
## 系统管理路由 (system.rs)
### 路由定义
```rust
pub fn routes() -> Router {
Router::new()
.route("/info", get(get_system_info))
.route("/status", get(get_system_status))
.route("/health", get(health_check))
.route("/metrics", get(get_metrics))
.route("/config", get(get_system_config).put(update_system_config))
.route("/cache/clear", post(clear_cache))
.route("/backup", post(create_backup))
.route("/restore", post(restore_backup))
}
```
### 接口实现
#### 系统状态监控
```rust
/// GET /api/system/status
/// 获取系统运行状态
pub async fn get_system_status(
State(app_state): State<AppState>,
Extension(current_user): Extension<CurrentUser>,
) -> Result<Json<ApiResponse<SystemStatus>>, AppError> {
// 权限检查
permission_service::check_user_permission(
&app_state.db,
&current_user.id,
"system",
"read",
).await?;
// 获取系统状态
let status = system_service::get_system_status(
&app_state.db,
&app_state.redis,
).await?;
Ok(Json(ApiResponse::success(status)))
}
```
#### 健康检查
```rust
/// GET /health
/// 系统健康检查
pub async fn health_check(
State(app_state): State<AppState>,
) -> Result<Json<HealthCheckResp>, AppError> {
let mut checks = HashMap::new();
// 数据库健康检查
let db_health = system_service::check_database_health(&app_state.db).await
.unwrap_or(HealthStatus::Unhealthy);
checks.insert("database".to_string(), db_health);
// Redis 健康检查
let redis_health = system_service::check_redis_health(&app_state.redis).await
.unwrap_or(HealthStatus::Unhealthy);
checks.insert("redis".to_string(), redis_health);
// 整体健康状态
let overall_status = if checks.values().all(|&status| status == HealthStatus::Healthy) {
HealthStatus::Healthy
} else {
HealthStatus::Unhealthy
};
Ok(Json(HealthCheckResp {
status: overall_status,
timestamp: Utc::now(),
checks,
}))
}
```
## 响应格式
### 统一响应结构
```rust
#[derive(Debug, Serialize)]
pub struct ApiResponse<T> {
pub success: bool,
pub data: Option<T>,
pub message: String,
pub code: u32,
pub timestamp: DateTime<Utc>,
}
impl<T> ApiResponse<T> {
pub fn success(data: T) -> Self {
Self {
success: true,
data: Some(data),
message: "操作成功".to_string(),
code: 200,
timestamp: Utc::now(),
}
}
pub fn error(message: String, code: u32) -> ApiResponse<()> {
ApiResponse {
success: false,
data: None,
message,
code,
timestamp: Utc::now(),
}
}
}
```
### 分页响应结构
```rust
#[derive(Debug, Serialize)]
pub struct PageResp<T> {
pub items: Vec<T>,
pub total: u64,
pub page: u64,
pub page_size: u64,
pub total_pages: u64,
pub has_next: bool,
pub has_prev: bool,
}
```
## 错误处理
### 错误类型定义
```rust
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("请求参数错误: {0}")]
BadRequest(String),
#[error("未授权访问")]
Unauthorized,
#[error("权限不足: {0}")]
Forbidden(String),
#[error("资源不存在: {0}")]
NotFound(String),
#[error("请求冲突: {0}")]
Conflict(String),
#[error("请求过于频繁")]
TooManyRequests,
#[error("内部服务器错误: {0}")]
InternalServerError(String),
}
```
### 错误响应处理
```rust
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, code, message) = match self {
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, 400, msg),
AppError::Unauthorized => (StatusCode::UNAUTHORIZED, 401, "未授权访问".to_string()),
AppError::Forbidden(msg) => (StatusCode::FORBIDDEN, 403, msg),
AppError::NotFound(msg) => (StatusCode::NOT_FOUND, 404, msg),
AppError::Conflict(msg) => (StatusCode::CONFLICT, 409, msg),
AppError::TooManyRequests => (StatusCode::TOO_MANY_REQUESTS, 429, "请求过于频繁".to_string()),
AppError::InternalServerError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, 500, msg),
};
let response = ApiResponse::<()>::error(message, code);
(status, Json(response)).into_response()
}
}
```
## 中间件
### 认证中间件
```rust
#[derive(Clone)]
pub struct AuthMiddleware {
jwt_secret: String,
}
impl AuthMiddleware {
pub fn new(jwt_secret: String) -> Self {
Self { jwt_secret }
}
}
#[async_trait]
impl<S> FromRequestParts<S> for CurrentUser
where
S: Send + Sync,
{
type Rejection = AppError;
async fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> Result<Self, Self::Rejection> {
// 从请求头获取 Token
let auth_header = parts.headers
.get(AUTHORIZATION)
.and_then(|header| header.to_str().ok())
.ok_or(AppError::Unauthorized)?;
// 验证 Bearer Token 格式
let token = auth_header
.strip_prefix("Bearer ")
.ok_or(AppError::Unauthorized)?;
// 验证 JWT Token
let claims = jwt::verify_token(token, &jwt_secret)
.map_err(|_| AppError::Unauthorized)?;
// 获取用户信息
let app_state = parts.extensions.get::<AppState>()
.ok_or(AppError::InternalServerError("应用状态未找到".to_string()))?;
let user = user_service::get_user_by_id(&app_state.db, &claims.user_id).await
.map_err(|e| AppError::InternalServerError(e.to_string()))?
.ok_or(AppError::Unauthorized)?;
Ok(CurrentUser {
id: user.id,
username: user.username,
roles: user.roles,
})
}
}
```
### 权限中间件
```rust
pub struct PermissionMiddleware {
resource: String,
action: String,
}
impl PermissionMiddleware {
pub fn new(resource: &str, action: &str) -> Self {
Self {
resource: resource.to_string(),
action: action.to_string(),
}
}
}
#[async_trait]
impl<S> FromRequestParts<S> for PermissionGuard
where
S: Send + Sync,
{
type Rejection = AppError;
async fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> Result<Self, Self::Rejection> {
// 获取当前用户
let current_user = CurrentUser::from_request_parts(parts, state).await?;
// 获取权限要求
let permission_req = parts.extensions.get::<PermissionRequirement>()
.ok_or(AppError::InternalServerError("权限要求未设置".to_string()))?;
// 检查权限
let app_state = parts.extensions.get::<AppState>()
.ok_or(AppError::InternalServerError("应用状态未找到".to_string()))?;
let has_permission = permission_service::check_user_permission(
&app_state.db,
&current_user.id,
&permission_req.resource,
&permission_req.action,
).await
.map_err(|e| AppError::InternalServerError(e.to_string()))?;
if !has_permission {
return Err(AppError::Forbidden("权限不足".to_string()));
}
Ok(PermissionGuard { current_user })
}
}
```
### 请求日志中间件
```rust
pub struct RequestLogMiddleware;
impl<S> Layer<S> for RequestLogMiddleware {
type Service = RequestLogService<S>;
fn layer(&self, inner: S) -> Self::Service {
RequestLogService { inner }
}
}
pub struct RequestLogService<S> {
inner: S,
}
impl<S> Service<Request<Body>> for RequestLogService<S>
where
S: Service<Request<Body>, Response = Response> + Clone + Send + 'static,
S::Future: Send + 'static,
{
type Response = S::Response;
type Error = S::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, request: Request<Body>) -> Self::Future {
let start_time = Instant::now();
let method = request.method().clone();
let uri = request.uri().clone();
let user_agent = request.headers()
.get(USER_AGENT)
.and_then(|h| h.to_str().ok())
.unwrap_or("")
.to_string();
let future = self.inner.call(request);
Box::pin(async move {
let response = future.await?;
let duration = start_time.elapsed();
info!(
target = "udmin",
method = %method,
uri = %uri,
status = %response.status(),
duration_ms = %duration.as_millis(),
user_agent = %user_agent,
"http.request.completed"
);
Ok(response)
})
}
}
```
## API 文档
### OpenAPI 集成
```rust
use utoipa::{OpenApi, ToSchema};
use utoipa_swagger_ui::SwaggerUi;
#[derive(OpenApi)]
#[openapi(
paths(
auth::login,
auth::logout,
user::list_users,
user::create_user,
flow::execute_flow,
),
components(
schemas(
LoginReq,
LoginResp,
UserDoc,
CreateUserReq,
ExecuteFlowReq,
ExecutionResult,
)
),
tags(
(name = "auth", description = "认证相关接口"),
(name = "user", description = "用户管理接口"),
(name = "flow", description = "流程管理接口"),
)
)]
struct ApiDoc;
pub fn create_swagger_routes() -> Router {
Router::new()
.merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()))
}
```
### 接口文档注解
```rust
#[utoipa::path(
post,
path = "/auth/login",
tag = "auth",
summary = "用户登录",
description = "用户名密码登录,返回 JWT Token",
request_body = LoginReq,
responses(
(status = 200, description = "登录成功", body = ApiResponse<LoginResp>),
(status = 400, description = "请求参数错误", body = ApiResponse<()>),
(status = 401, description = "用户名或密码错误", body = ApiResponse<()>),
)
)]
pub async fn login(
State(app_state): State<AppState>,
Json(req): Json<LoginReq>,
) -> Result<Json<ApiResponse<LoginResp>>, AppError> {
// 实现代码...
}
```
## 性能优化
### 请求缓存
```rust
pub struct CacheMiddleware {
redis: RedisConnection,
ttl: Duration,
}
impl CacheMiddleware {
pub fn new(redis: RedisConnection, ttl: Duration) -> Self {
Self { redis, ttl }
}
async fn get_cache_key(&self, request: &Request<Body>) -> String {
let method = request.method();
let uri = request.uri();
let query = uri.query().unwrap_or("");
format!("api_cache:{}:{}:{}", method, uri.path(), query)
}
}
```
### 响应压缩
```rust
pub fn create_compression_layer() -> CompressionLayer {
CompressionLayer::new()
.gzip(true)
.br(true)
.deflate(true)
.quality(CompressionLevel::Default)
}
```
### 请求限流
```rust
pub struct RateLimitMiddleware {
redis: RedisConnection,
max_requests: u32,
window: Duration,
}
impl RateLimitMiddleware {
pub async fn check_rate_limit(
&self,
client_id: &str,
) -> Result<bool, AppError> {
let key = format!("rate_limit:{}", client_id);
let current_count: u32 = self.redis.get(&key).await.unwrap_or(0);
if current_count >= self.max_requests {
return Ok(false);
}
let _: () = self.redis.incr(&key, 1).await?;
let _: () = self.redis.expire(&key, self.window.as_secs() as usize).await?;
Ok(true)
}
}
```
## 测试策略
### 单元测试
```rust
#[cfg(test)]
mod tests {
use super::*;
use axum_test::TestServer;
#[tokio::test]
async fn test_login_success() {
let app = create_test_app().await;
let server = TestServer::new(app).unwrap();
let response = server
.post("/auth/login")
.json(&json!({
"username": "admin",
"password": "password123"
}))
.await;
response.assert_status_ok();
let body: ApiResponse<LoginResp> = response.json();
assert!(body.success);
assert!(body.data.is_some());
}
#[tokio::test]
async fn test_login_invalid_credentials() {
let app = create_test_app().await;
let server = TestServer::new(app).unwrap();
let response = server
.post("/auth/login")
.json(&json!({
"username": "admin",
"password": "wrong_password"
}))
.await;
response.assert_status(StatusCode::UNAUTHORIZED);
}
}
```
### 集成测试
```rust
#[tokio::test]
async fn test_user_crud_flow() {
let app = create_test_app().await;
let server = TestServer::new(app).unwrap();
// 登录获取 Token
let login_response = server
.post("/auth/login")
.json(&json!({
"username": "admin",
"password": "password123"
}))
.await;
let login_body: ApiResponse<LoginResp> = login_response.json();
let token = login_body.data.unwrap().token;
// 创建用户
let create_response = server
.post("/api/users")
.add_header(AUTHORIZATION, format!("Bearer {}", token))
.json(&json!({
"username": "test_user",
"password": "password123",
"email": "test@example.com"
}))
.await;
create_response.assert_status_ok();
let create_body: ApiResponse<UserDoc> = create_response.json();
let user_id = create_body.data.unwrap().id;
// 获取用户
let get_response = server
.get(&format!("/api/users/{}", user_id))
.add_header(AUTHORIZATION, format!("Bearer {}", token))
.await;
get_response.assert_status_ok();
// 删除用户
let delete_response = server
.delete(&format!("/api/users/{}", user_id))
.add_header(AUTHORIZATION, format!("Bearer {}", token))
.await;
delete_response.assert_status_ok();
}
```
## 最佳实践
### 路由设计
- **RESTful 风格**: 遵循 REST API 设计原则
- **资源命名**: 使用复数名词表示资源
- **HTTP 方法**: 正确使用 GET、POST、PUT、DELETE
- **状态码**: 返回合适的 HTTP 状态码
### 参数验证
- **输入验证**: 使用 validator 进行参数验证
- **类型安全**: 使用强类型结构体
- **错误信息**: 提供清晰的验证错误信息
- **安全过滤**: 过滤恶意输入
### 错误处理
- **统一格式**: 使用统一的错误响应格式
- **错误分类**: 合理分类不同类型的错误
- **日志记录**: 记录详细的错误日志
- **用户友好**: 提供用户友好的错误信息
### 安全考虑
- **认证授权**: 实现完善的认证授权机制
- **输入验证**: 严格验证所有输入参数
- **HTTPS**: 在生产环境使用 HTTPS
- **CORS**: 正确配置 CORS 策略