67 lines
2.1 KiB
Rust
Raw Normal View History

//! 统一错误处理
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use serde_json::json;
/// 应用统一错误类型
#[derive(thiserror::Error, Debug)]
#[allow(dead_code)]
pub enum AppError {
#[error("数据库错误: {0}")]
Database(#[from] sqlx::Error),
#[error("Redis错误: {0}")]
Redis(#[from] redis::RedisError),
#[error("未找到: {0}")]
NotFound(String),
#[error("参数错误: {0}")]
BadRequest(String),
#[error("未授权: {0}")]
Unauthorized(String),
#[error("无权限: {0}")]
Forbidden(String),
#[error("请求过于频繁: {0}")]
TooManyRequests(String),
#[error("内部错误: {0}")]
Internal(String),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, code, message) = match &self {
AppError::Database(e) => {
tracing::error!("数据库错误: {}", e);
(StatusCode::INTERNAL_SERVER_ERROR, "DATABASE_ERROR", "服务器内部错误")
}
AppError::Redis(e) => {
tracing::error!("Redis错误: {}", e);
(StatusCode::INTERNAL_SERVER_ERROR, "REDIS_ERROR", "缓存服务错误")
}
AppError::NotFound(msg) => (StatusCode::NOT_FOUND, "NOT_FOUND", msg.as_str()),
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, "BAD_REQUEST", msg.as_str()),
AppError::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, "UNAUTHORIZED", msg.as_str()),
AppError::Forbidden(msg) => (StatusCode::FORBIDDEN, "FORBIDDEN", msg.as_str()),
AppError::TooManyRequests(msg) => (StatusCode::TOO_MANY_REQUESTS, "TOO_MANY_REQUESTS", msg.as_str()),
AppError::Internal(msg) => {
tracing::error!("内部错误: {}", msg);
(StatusCode::INTERNAL_SERVER_ERROR, "INTERNAL_ERROR", "服务器内部错误")
}
};
let body = json!({
"code": code,
"message": message,
});
(status, Json(body)).into_response()
}
}