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}