Skip to main content

tdm_server_rust/common/
json_extractor.rs

1//! 高性能 JSON 请求体提取器 (JSON Extractor)
2//!
3//! 实现 axum [`FromRequest`] trait,使用 simd-json 加速反序列化。
4//! 当 simd-json 不支持目标类型时自动回退到 serde_json。
5
6use axum::{
7    body::Bytes,
8    extract::{FromRequest, Request},
9    http::{header, StatusCode},
10    response::{IntoResponse, Response},
11};
12use async_trait::async_trait;
13use serde::de::DeserializeOwned;
14
15use crate::utils::fast_json;
16
17/// 高性能 JSON 请求体包装器
18///
19/// 作为 axum handler 参数使用时,自动从请求 body 中提取并反序列化 JSON。
20/// 优先使用 simd-json 进行解析,失败时回退到 serde_json。
21///
22/// ## 使用示例
23///
24/// ```rust,ignore
25/// async fn login_handler(
26///     AppJson(body): AppJson<MemberLoginRequest>,
27/// ) -> impl IntoResponse {
28///     // body 已经是 MemberLoginRequest 实例
29/// }
30/// ```
31///
32/// ## 错误处理
33///
34/// body 为空或 JSON 解析失败时,返回 400 状态码和 JSON 格式错误信息:
35///
36/// ```json
37/// {"code":500,"msg":"解析错误详情","data":null}
38/// ```
39pub struct AppJson<T>(pub T);
40
41#[async_trait]
42impl<T, S> FromRequest<S> for AppJson<T>
43where
44    T: DeserializeOwned,
45    S: Send + Sync,
46{
47    /// 解析失败时返回 400 JSON
48    type Rejection = Response;
49
50    /// 读取 body 并反序列化
51    async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
52        let bytes = Bytes::from_request(req, state)
53            .await
54            .map_err(|err| err.into_response())?;
55        if bytes.is_empty() {
56            return Err(json_error(
57                StatusCode::BAD_REQUEST,
58                "Request body is empty",
59            ));
60        }
61        fast_json::from_slice(&bytes)
62            .map(AppJson)
63            .map_err(|e| json_error(StatusCode::BAD_REQUEST, &e.to_string()))
64    }
65}
66
67/// 构造 JSON 错误响应
68fn json_error(status: StatusCode, msg: &str) -> Response {
69    (
70        status,
71        [(header::CONTENT_TYPE, "application/json;charset=UTF-8")],
72        format!(r#"{{"code":500,"msg":"{msg}","data":null}}"#),
73    )
74        .into_response()
75}