easy_msr_api/
error.rs

1//! # 错误处理模块
2//! 
3//! 定义了项目中使用的错误类型和错误处理机制。
4//! 
5//! 提供了统一的错误类型`AppError`,用于处理各种可能的错误情况,
6//! 包括网络请求错误、配置错误、资源未找到等。
7
8use axum::{
9    http::StatusCode,
10    response::{IntoResponse, Response},
11};
12use thiserror::Error;
13
14/// 应用程序错误类型
15/// 
16/// 枚举了所有可能的错误情况,并为每种错误提供了清晰的描述。
17/// 实现了`IntoResponse`,可以直接作为Axum的响应返回。
18#[derive(Error, Debug)]
19pub enum AppError {
20    /// 远程API请求错误
21    /// 
22    /// 包含底层`reqwest::Error`的详细信息
23    #[error("远程API请求错误: {0}")]
24    Remote(#[from] reqwest::Error),
25    
26    /// 无效的输入参数
27    /// 
28    /// 当请求参数不符合要求时返回
29    #[error("无效的输入参数: {0}")]
30    BadRequest(String),
31    
32    /// 请求的资源不存在
33    /// 
34    /// 当请求的资源(歌曲、专辑、新闻等)不存在时返回
35    #[error("请求的资源不存在")]
36    NotFound,
37    
38    /// 服务器内部错误
39    /// 
40    /// 当发生未预期的内部错误时返回
41    #[error("服务器内部错误: {0}")]
42    Internal(String),
43    
44    /// 配置错误
45    /// 
46    /// 当环境变量或配置文件格式不正确时返回
47    #[error("配置错误: {0}")]
48    Config(String),
49}
50
51impl IntoResponse for AppError {
52    /// 将错误转换为HTTP响应
53    /// 
54    /// 根据不同的错误类型返回相应的HTTP状态码和错误信息:
55    /// - 请求超时 -> 408 Request Timeout
56    /// - 远程服务错误 -> 502 Bad Gateway
57    /// - 参数错误 -> 400 Bad Request
58    /// - 资源未找到 -> 404 Not Found
59    /// - 内部错误 -> 500 Internal Server Error
60    /// - 配置错误 -> 500 Internal Server Error
61    fn into_response(self) -> Response {
62        let (status, message) = match self {
63            AppError::Remote(ref e) if e.is_timeout() => (StatusCode::REQUEST_TIMEOUT, "请求超时"),
64            AppError::Remote(_) => (StatusCode::BAD_GATEWAY, "远程服务暂时不可用"),
65            AppError::BadRequest(ref msg) => (StatusCode::BAD_REQUEST, msg.as_str()),
66            AppError::NotFound => (StatusCode::NOT_FOUND, "请求的资源不存在"),
67            AppError::Internal(_) => (StatusCode::INTERNAL_SERVER_ERROR, "服务器内部错误"),
68            AppError::Config(_) => (StatusCode::INTERNAL_SERVER_ERROR, "配置错误"),
69        };
70        
71        let body = serde_json::json!({
72            "error": message,
73            "code": status.as_u16()
74        });
75        
76        (status, axum::Json(body)).into_response()
77    }
78}