【技术布局】Rust Axum 如何优雅的返回数据
【技术布局】Rust Axum 如何优雅的返回数据
一、背景说明最近在用rust写一套web脚手架,在定义返回结果的时候发现axum自带的返回写法挺丑的,所以打算简单封装下。这一部分使用到的库主要为:axumtokioserdethiserror二、通用返回体在当前设计下,暂且假定只要服务器接收到客户端请求,统一返回状态码为200,返回的结构体中包含结果状态码、消息、内容三个部分。由于axum的返
【技术布局】Rust Axum 如何优雅的返回数据
一、背景说明
最近在用rust写一套web脚手架,在定义返回结果的时候发现axum自带的返回写法挺丑的,所以打算简单封装下。这一部分使用到的库主要为:
- axum
- tokio
- serde
- thiserror
二、通用返回体
在当前设计下,暂且假定只要服务器接收到客户端请求,统一返回状态码为200,返回的结构体中包含结果状态码、消息、内容三个部分。由于axum的返回都需要实现IntoRespe trait。同时再为它提供两个方法用于创建对象。
代码语言:rust复制use axum::http::StatusCode;
use axum::{respe::IntoRespe, Json};
use serde::Serialize;
use serde_json::json;
// 成功响应码和信息
ct SUCCESS_CODE: i2 = StatusCode::OK.as_u16() as i2;
ct SUCCESS_MESSAGE: &str = "success";
/// 响应结构体
#[derive(Debug, Serialize)]
pub struct ApiResult<T> {
code: i2, // 响应码,通常用于表示请求的结果状态
data: Option<T>, // 可选的数据部分,包含请求成功时返回的数据
message: String, // 响应信息,描述请求的结果或错误信息
}
// 实现 `IntoRespe` trait 以将 ApiResult 转换为 Axum 响应
impl<T: Serialize> IntoRespe for ApiResult<T> {
fn into_respe(self) -> axum::respe::Respe {
let val = json!(self); // 将 ApiResult 转换为 JSO 格式
Json(val).into_respe() // 将 JSO 响应转换为 Axum 的响应格式
}
}
// 封装成功和错误响应
impl<T> ApiResult<T> {
/// 成功响应
/// 响应码为 200, 响应信息为 "success", data 为传入的 data 可选
pub fn success(data: T) -> Self {
Self {
code: SUCCESS_CODE, // 成功状态码
data: Some(data), // 包含成功时返回的数据
message: SUCCESS__owned(), // 成功信息
}
}
/// 错误响应
/// 指定错误码和错误信息
pub fn error(code: i2, message: String) -> Self {
Self {
code: code, // 错误状态码
data: one, // 不包含数据
message: message, // 错误信息
}
}
}
三、通用异常
在系统中提供一个统一的全局异常,包装所有其他的异常,并且提供可扩展的异常信息。然后为它实现IntoRespe的trait,将所有异常信息匹配为ApiResult对象返回给客户端。
下面代码中的 DatabaseError
是匹配该异常,创建为ApiError
异常。
同时提供一个map_db_error
方法,用于在可能会抛出sea_orm::DbErr
的地方通过.map_err(map_db_error)
来转化成ApiErr
并向上抛出。
use axum::{
http::StatusCode,
respe::{IntoRespe, Respe},
};
use thiserror::Error;
use super::api_result::ApiResult;
/// 定义 API 错误类型
#[derive(Error, Debug)]
pub enum ApiError {
// 数据库错误,允许将 sea_orm::DbErr 转换为 ApiError
#[error(transparent)]
DatabaseError(#[from] sea_orm::DbErr),
// 其他错误,包含错误信息
#[error("服务异常: {0}")]
OtherError(String),
}
/// 实现 IntoRespe trait 以将 ApiError 转换为 Axum 响应
impl IntoRespe for ApiError {
fn into_respe(self) -> Respe {
// 根据错误类型生成相应的状态码和消息
let (status_code, message) = match &self {
ApiError::DatabaseError(msg) => (StatusCode::ITERAL_SERVER_ERROR, _string()),
ApiError::OtherError(msg) => (StatusCode::ITERAL_SERVER_ERROR, _string()),
};
// 构建 ApiResult 错误响应并转换为 Axum 响应
let into_respe_tuple = (
StatusCode::OK, // 这里的状态码可以根据需要调整
ApiResult::<()>::error(status_code.as_u16() as i2, message), // 使用 ApiResult 构建错误响应
)
.into_respe();
into_respe_tuple.into_respe() // 返回最终的响应
}
}
pub fn map_db_error(err: sea_orm::DbErr) -> ApiError {
ApiError::DatabaseError(err)
}
四、路由handler
项目中所有的路由handler都统一返回Result<ApiResult<T>,ApiError>
结构。
pub async fn test_handler() -> Result<ApiResult<ResStruct>, ApiError> {
let res = ResStruct {}
Ok(ApiResult::success(res))
}
五、请求处理
一般不会在handler中直接处理请求,所以会有一个单独的处理函数,处理函数一般情况返回Result<ResStruct,ApiError>
对象,如果遇到其他可能会抛出的异常,则通过map_err函数传入对应的转化函数来转化成ApiError。如下,在发生异常时转化为ApiError返回,如果处理正常则返回实际结果。
let async fn test_service(db: &DatabaseConnection)
-> Result<system_account::Entity, ApiError> {
let option = system_account::Entity::find()
.filter(system_account::Column::(login_req.()))
.order_by_asc(system_account::Column::Id)
.one(db)
.await
.map_err(map_db_error)?; // 这里转化数据库异常为ApiError
if option.is_none() {
// 这里返回自定义的异常信息
return Err(ApiError::OtherError("用户不存在!".to_string()));
}
Ok(option.unwrap())
}
六、结果展示
附上两张请求通过和异常的截图:
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
上传时间: 2025-07-21 14:14:24
推荐阅读
留言与评论(共有 18 条评论) |
本站网友 温江二手房 | 17分钟前 发表 |
处理函数一般情况返回Result<ResStruct | |
本站网友 天津搜房网二手房 | 29分钟前 发表 |
本站网友 老牛自知夕阳晚 | 10分钟前 发表 |
// 使用 ApiResult 构建错误响应 ) .into_respe(); into_respe_tuple.into_respe() // 返回最终的响应 } } pub fn map_db_error(err | |
本站网友 罗汉果泡水喝的功效 | 27分钟前 发表 |
返回的结构体中包含结果状态码 | |
本站网友 过塘蛇 | 3分钟前 发表 |
Serialize; use serde_json | |
本站网友 东阿房屋出租 | 15分钟前 发表 |
{0}")] OtherError(String) | |
本站网友 csdn登录 | 25分钟前 发表 |
error(status_code.as_u16() as i2 | |
本站网友 真艾叶和假艾叶图片 | 0秒前 发表 |
// 错误信息 } } }三 | |
本站网友 长期食用螺旋藻至胃癌 | 15分钟前 发表 |
本站网友 藿香的功效与作用 | 4分钟前 发表 |
ApiError> { let res = ResStruct {} Ok(ApiResult | |
本站网友 孙开林 | 6分钟前 发表 |
DbErr的地方通过.map_err(map_db_error)来转化成ApiErr并向上抛出 | |
本站网友 清淡的菜 | 6分钟前 发表 |
通用异常在系统中提供一个统一的全局异常 | |
本站网友 泉州美容培训 | 4分钟前 发表 |
如下 | |
本站网友 我可以摸你的胸吗 | 23分钟前 发表 |
(login_req.())) .order_by_asc(system_account | |
本站网友 橄榄油什么作用 | 1分钟前 发表 |
// 其他错误 | |
本站网友 无线路由器信号增强 | 15分钟前 发表 |
如果处理正常则返回实际结果 | |
本站网友 修护霜 | 27分钟前 发表 |