You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust JSON反序列化失败求助:结构体与JSON格式匹配问题

Rust Serde反序列化失败排查方案

我是Rust新手,调用API获取到如下格式的JSON(以debug形式展示):

Array([
    Object({
        "columns": Array([
            String(
                "attr",
            ),
            String(
                "user_count",
            ),
        ]),
        "data": Array([
            Object({
                "meta": Array([
                    Null,
                    Null,
                ]),
                "row": Array([
                    Array([
                        String(
                            "Built-in account for administering the computer/domain",
                        ),
                    ]),
                    Number(
                        1,
                    ),
                ]),
            }),
        ]),
    }),
])

我定义了对应的序列化结构体:

#[derive(Serialize, Deserialize, Debug)]
pub struct ResolvedAttribute {
    pub columns: Vec<Option<String>>,
    pub data: Vec<MetaData>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MetaData {
    pub meta: Vec<Option<String>>,
    pub row: (Vec<Vec<Option<String>>>, i64),
}

执行反序列化代码时触发panic:

let res = REQWEST_MTLS.post(&uri).json(&req).send().await.unwrap();

//println!("res {:#?}", res);

if !res.status().is_success() {
    let body: Value = res.json().await.unwrap();
    println!("Error: {:#}", body);
    panic!();
}

let res: Value = res.json().await.unwrap();

println!("res {:#?}", res);

let root: Vec<ResolvedAttribute> = match serde_json::from_value(res.clone()) {
    Ok(r) => r,
    Err(e) => {
        println!("{:#}\nError:{:#?}", res, e);
        panic!("Deserialization Error.");
    }
};
  
return root

错误信息:

thread 'main' panicked at 'Deserialization Error.


排查方向

1. 响应体被重复读取导致无数据可用

reqwest的Response是流式结构,只能被读取一次。你的代码中:

  • 请求失败时,调用res.json().await读取了响应体;
  • 请求成功时,再次调用res.json().await,此时响应体已被消费,无法读取有效数据,直接引发反序列化失败。

修复方案:先完整读取并保存响应体,再进行后续处理:

let res = REQWEST_MTLS.post(&uri).json(&req).send().await.unwrap();
let status = res.status();
// 先读取响应体字节保存,避免重复读取
let body_bytes = res.bytes().await.unwrap();

if !status.is_success() {
    let body: Value = serde_json::from_slice(&body_bytes).unwrap();
    println!("Error: {:#}", body);
    panic!();
}

// 从保存的字节中解析JSON
let res: Value = serde_json::from_slice(&body_bytes).unwrap();
println!("res {:#?}", res);

let root: Vec<ResolvedAttribute> = match serde_json::from_value(res.clone()) {
    Ok(r) => r,
    Err(e) => {
        println!("{:#}\nError:{:#?}", res, e);
        panic!("Deserialization Error.");
    }
};
  
return root

2. 打印完整的Serde错误信息

当前panic仅输出通用提示,未展示Serde的具体错误详情(如字段类型不匹配、数组长度不兼容等)。确保在错误分支中完整打印e的内容:

Err(e) => {
    println!("响应内容:\n{:#}\n反序列化错误详情:\n{:#?}", res, e);
    panic!("Deserialization Error.");
}

通过具体错误信息可快速定位结构体与JSON格式不匹配的具体位置。

3. 核对结构体与JSON的类型匹配度

逐一校验字段定义:

  • columns:JSON中是["attr", "user_count"](非空字符串数组),结构体定义Vec<Option<String>>兼容,但可简化为Vec<String>(若确定无null值);
  • row:JSON中是[[String], Number],结构体定义(Vec<Vec<Option<String>>>, i64),需确认JSON中row的第一个元素始终是嵌套数组,若为单层数组则需调整为(Vec<Option<String>>, i64);
  • meta:JSON中是[Null, Null],结构体定义Vec<Option<String>>完全匹配,无问题。

内容的提问来源于stack exchange,提问作者JGilmartin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 20:45:55