Skip to main content

axum_bootstrap/
error.rs

1//! # 错误处理模块
2//!
3//! 提供统一的错误类型 `AppError`,用于在 Axum 应用中处理各种错误
4//!
5//! # 主要特性
6//! - 包装 `anyhow::Error`,提供灵活的错误处理
7//! - 自动实现 `IntoResponse`,可直接在路由处理器中返回
8//! - 支持 `?` 操作符,自动转换标准错误类型
9//! - 统一的错误响应格式 (HTTP 500)
10//!
11//! # 示例
12//!
13//! ```no_run
14//! use axum_bootstrap::error::AppError;
15//! use axum::response::IntoResponse;
16//!
17//! async fn handler() -> Result<impl IntoResponse, AppError> {
18//!     // 可以直接使用 ? 操作符
19//!     let _result = std::fs::read_to_string("file.txt")?;
20//!     Ok("success")
21//! }
22//! ```
23
24use anyhow::anyhow;
25use std::fmt::Display;
26
27use axum::response::{IntoResponse, Response};
28use hyper::StatusCode;
29
30/// 应用程序错误类型
31///
32/// 包装 `anyhow::Error`,提供统一的错误处理和响应转换
33///
34/// # 说明
35/// 该错误类型会自动将所有错误转换为 HTTP 500 响应,
36/// 并记录详细的错误日志(使用 tracing)
37#[derive(Debug)]
38pub struct AppError(anyhow::Error);
39
40impl Display for AppError {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        self.0.fmt(f)
43    }
44}
45
46/// 实现 Axum 响应转换
47///
48/// 将错误转换为 HTTP 500 响应,并记录错误日志
49impl IntoResponse for AppError {
50    fn into_response(self) -> Response {
51        let err = self.0;
52        // TraceLayer 已经包含了请求方法、URI 等信息,这里不需要重复记录
53        tracing::error!(%err, "error");
54        (StatusCode::INTERNAL_SERVER_ERROR, format!("ERROR: {}", &err)).into_response()
55    }
56}
57
58/// 自动转换其他错误类型为 AppError
59///
60/// 这使得可以在返回 `Result<_, AppError>` 的函数中直接使用 `?` 操作符
61///
62/// # 示例
63///
64/// ```no_run
65/// # use axum_bootstrap::error::AppError;
66/// fn my_function() -> Result<(), AppError> {
67///     // 自动转换 std::io::Error 为 AppError
68///     let _content = std::fs::read_to_string("file.txt")?;
69///     Ok(())
70/// }
71/// ```
72impl<E> From<E> for AppError
73where
74    E: Into<anyhow::Error>,
75{
76    fn from(err: E) -> Self {
77        Self(err.into())
78    }
79}
80
81impl AppError {
82    /// 从标准错误类型创建 AppError
83    ///
84    /// # 参数
85    /// - `err`: 任何实现了 `std::error::Error + Send + Sync` 的错误
86    ///
87    /// # 返回
88    /// 包装后的 AppError
89    pub fn new<T: std::error::Error + Send + Sync + 'static>(err: T) -> Self {
90        Self(anyhow!(err))
91    }
92}