1use axum::{
2 http::StatusCode,
3 response::{IntoResponse, Response},
4 Json,
5};
6use serde_json::json;
7use thiserror::Error;
8
9#[derive(Error, Debug)]
11pub enum AppError {
12 #[error("内部服务器错误: {0}")]
13 Internal(#[from] anyhow::Error),
14
15 #[error("未找到资源")]
16 NotFound,
17
18 #[error("未授权访问")]
19 Unauthorized,
20
21 #[error("禁止访问")]
22 Forbidden,
23
24 #[error("请求参数错误: {0}")]
25 BadRequest(String),
26
27 #[error("配置错误: {0}")]
28 Config(#[from] config::ConfigError),
29
30 #[cfg(feature = "database")]
32 #[error("数据库错误: {0}")]
33 Database(#[from] sqlx::Error),
34
35 #[cfg(feature = "database")]
37 #[error("数据库连接池未初始化")]
38 DatabaseNotInitialized,
39
40 #[cfg(feature = "redis")]
42 #[error("Redis 错误: {0}")]
43 Redis(#[from] redis::RedisError),
44
45 #[cfg(feature = "redis")]
47 #[error("Redis 客户端未初始化")]
48 RedisNotInitialized,
49}
50
51pub type AppResult<T> = Result<T, AppError>;
53
54impl IntoResponse for AppError {
55 fn into_response(self) -> Response {
56 let (status, error_message) = match self {
57 AppError::NotFound => (StatusCode::NOT_FOUND, self.to_string()),
58 AppError::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()),
59 AppError::Forbidden => (StatusCode::FORBIDDEN, self.to_string()),
60 AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
61 AppError::Config(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
62 #[cfg(feature = "database")]
63 AppError::Database(e) => {
64 tracing::error!("数据库错误: {:?}", e);
65 (
66 StatusCode::INTERNAL_SERVER_ERROR,
67 format!("数据库错误: {}", e),
68 )
69 }
70 #[cfg(feature = "database")]
71 AppError::DatabaseNotInitialized => {
72 tracing::error!("数据库连接池未初始化");
73 (
74 StatusCode::INTERNAL_SERVER_ERROR,
75 "数据库连接池未初始化".to_string(),
76 )
77 }
78 #[cfg(feature = "redis")]
79 AppError::Redis(e) => {
80 tracing::error!("Redis 错误: {:?}", e);
81 (
82 StatusCode::INTERNAL_SERVER_ERROR,
83 format!("Redis 错误: {}", e),
84 )
85 }
86 #[cfg(feature = "redis")]
87 AppError::RedisNotInitialized => {
88 tracing::error!("Redis 客户端未初始化");
89 (
90 StatusCode::INTERNAL_SERVER_ERROR,
91 "Redis 客户端未初始化".to_string(),
92 )
93 }
94 AppError::Internal(e) => {
95 tracing::error!("内部错误: {:?}", e);
96 (
97 StatusCode::INTERNAL_SERVER_ERROR,
98 "内部服务器错误".to_string(),
99 )
100 }
101 };
102
103 let body = Json(json!({
104 "error": error_message,
105 "status": status.as_u16(),
106 }));
107
108 (status, body).into_response()
109 }
110}