Axum 的错误模型,最大的特点就是:
简单,而且可预测。
官方文档专门强调过一个很反直觉但很重要的点:
async fn handler() -> Result<String, StatusCode> {
Err(StatusCode::NOT_FOUND)
}这里的 Err(StatusCode::NOT_FOUND),在 Axum 看来不是框架级错误。
它只是:
一个能被转换成 Response 的值也就是说,在 Axum 里你应该这样想:
Err(ApiError)
= 拒签通知
= 业务层面的“不给过”
= 依然是正常 HTTP 响应路径的一部分所以最常见的做法,就是定义自己的错误类型并实现 IntoResponse:
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 里就可以舒服地写:
async fn get_permit(...) -> Result<Json<Permit>, ApiError> {
// ...
}这套模型很像:
窗口办事失败
不是海关大楼塌了
而是窗口给出一张标准拒签通知单