Skip to main content

cool_core/middleware/
exception.rs

1//! 异常过滤器中间件
2//!
3//! 对应 TypeScript 版本的 `exception/filter.ts`
4//!
5//! 提供全局异常处理,统一错误响应格式
6
7use crate::constant::ResCode;
8use crate::error::CoolError;
9use salvo::prelude::*;
10use serde::Serialize;
11use tracing::error;
12
13/// 错误响应结构
14#[derive(Debug, Serialize)]
15pub struct ErrorResponse {
16    /// 错误码
17    pub code: i32,
18    /// 错误消息
19    pub message: String,
20}
21
22/// 异常过滤器中间件
23///
24/// 捕获所有异常并统一格式化为错误响应
25///
26/// 对应 TypeScript 版本的 `exception/filter.ts`
27///
28/// 注意:在 Salvo 中,错误通常通过 `?` 操作符自动转换为 HTTP 响应。
29/// 这个中间件主要用于统一错误响应格式,确保所有错误都返回统一的 JSON 格式。
30pub struct ExceptionFilter;
31
32#[async_trait::async_trait]
33impl Handler for ExceptionFilter {
34    async fn handle(
35        &self,
36        req: &mut Request,
37        depot: &mut Depot,
38        res: &mut Response,
39        ctrl: &mut FlowCtrl,
40    ) {
41        // 先执行后续处理器
42        ctrl.call_next(req, depot, res).await;
43
44        // 获取状态码
45        let status = res.status_code.unwrap_or(StatusCode::OK);
46
47        // 如果响应状态码是错误状态码,且还没有设置响应体,则统一格式化
48        if status.is_client_error() || status.is_server_error() {
49            // 检查是否已经有响应体
50            if res.body.is_none() {
51                // 尝试从 depot 获取错误信息
52                if let Ok(err_msg) = depot.get::<String>("error") {
53                    error!("Request error: {}", err_msg);
54                    let error_response = ErrorResponse {
55                        code: status.as_u16() as i32,
56                        message: err_msg.clone(),
57                    };
58                    res.render(Json(error_response));
59                } else {
60                    // 默认错误响应
61                    let error_response = ErrorResponse {
62                        code: ResCode::CommError.code(),
63                        message: "请求处理失败".to_string(),
64                    };
65                    res.render(Json(error_response));
66                }
67            }
68        }
69    }
70}
71
72/// 创建异常过滤器中间件
73pub fn exception_filter() -> ExceptionFilter {
74    ExceptionFilter
75}
76
77/// 错误处理辅助函数
78///
79/// 将 CoolError 转换为统一的错误响应
80pub fn handle_error(err: &CoolError) -> ErrorResponse {
81    error!("CoolError: {:?}", err);
82    ErrorResponse {
83        code: err.code().code(),
84        message: err.to_string(),
85    }
86}