全书目录

第三十九篇:Axum 完全指南 —— Rust 类型关口宇宙

第十四章:错误处理 —— Axum 的“错误”不是你以为的那种错误

1 分钟 196 字 第 760 / 962 个阅读单元

Axum 的错误模型,最大的特点就是:

简单,而且可预测。

官方文档专门强调过一个很反直觉但很重要的点:

rust
async fn handler() -> Result<String, StatusCode> {
    Err(StatusCode::NOT_FOUND)
}

这里的 Err(StatusCode::NOT_FOUND),在 Axum 看来不是框架级错误

它只是:

text
一个能被转换成 Response 的值

也就是说,在 Axum 里你应该这样想:

text
Err(ApiError)
= 拒签通知
= 业务层面的“不给过”
= 依然是正常 HTTP 响应路径的一部分

所以最常见的做法,就是定义自己的错误类型并实现 IntoResponse

rust
use axum::{
    http::StatusCode,
    response::{IntoResponse, Response},
    Json,
};

#[derive(Debug)]
enum ApiError {
    Unauthorized,
    NotFound,
    Conflict(&'static str),
}

impl IntoResponse for ApiError {
    fn into_response(self) -> Response {
        let (status, message) = match self {
            Self::Unauthorized => (StatusCode::UNAUTHORIZED, "没有通关权限"),
            Self::NotFound => (StatusCode::NOT_FOUND, "找不到对应报关单"),
            Self::Conflict(msg) => (StatusCode::CONFLICT, msg),
        };

        (
            status,
            Json(serde_json::json!({
                "success": false,
                "error": message
            })),
        )
            .into_response()
    }
}

然后 handler 里就可以舒服地写:

rust
async fn get_permit(...) -> Result<Json<Permit>, ApiError> {
    // ...
}

这套模型很像:

text
窗口办事失败
不是海关大楼塌了
而是窗口给出一张标准拒签通知单