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

Rust使用serde_json反序列化API返回JSON数据结构不匹配报错

问题背景
  • 目标:抓取OSRS Wiki公开价格接口返回的JSON数据,接口地址为 https://prices.runescape.wiki/api/v1/osrs/latest
  • 先后尝试两种结构体定义方案,均触发相同反序列化报错,移除serde_with嵌套解析配置后问题仍未解决
  • 运行时报错信息:
Error: reqwest::Error { kind: Decode, source: Error("invalid type: map, expected valid json object", line: 1, column: 8)

原有问题核心代码:

#[derive(Serialize, Deserialize, Debug)]
struct Latest {
    high: u32,
    highTime: String,
    low: String,
    lowTime: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Data {
    #[serde(with = "serde_with::json::nested")]
    data: Vec<Latest>,
}

#[derive(Serialize, Deserialize, Debug)]
struct Datav2 {
    #[serde(with = "serde_with::json::nested")]
    data: HashMap<u32, Vec<Latest>>,
}
#[cfg(not(target_arch = "wasm32"))]
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
     let res = reqwest::get(url).await?;
    let response = &res.json::<Datav2>().await?;
}
问题根因

代码存在4个核心问题,直接触发反序列化报错:

  • 误用serde_with::json::nested配置:该配置仅用于解析被转义为字符串的嵌套JSON内容,目标接口返回的data字段是原生JSON对象,添加该配置会让serde尝试将原生Map类型按字符串规则解析,直接触发类型不匹配错误
  • 嵌套类型定义错误:接口返回的每个数字ID对应的价格条目是单值对象,不是数组,不需要用Vec<Latest>包裹
  • 字段可见性错误:Rust结构体默认字段为私有,serde反序列化需要字段拥有公开可见性,常规实现直接为字段添加pub修饰即可
  • 基础类型定义错误:接口返回的highTime/lowTime是Unix时间戳数值类型,low字段和high字段一致为无符号整数,均不是字符串类型
正确实现

首先配置Cargo.toml依赖:

[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }

核心业务代码:

use std::collections::HashMap;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Latest {
    // 用Option包裹是因为部分无交易记录的物品会返回null值,避免反序列化失败
    pub high: Option<u32>,
    pub highTime: Option<u64>,
    pub low: Option<u32>,
    pub lowTime: Option<u64>,
}

#[derive(Serialize, Deserialize, Debug)]
struct PriceResponse {
    // 移除错误的serde_with嵌套解析配置,data本身就是ID到价格对象的Map
    pub data: HashMap<u32, Latest>,
}

#[cfg(not(target_arch = "wasm32"))]
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let url = "https://prices.runescape.wiki/api/v1/osrs/latest";
    let res = reqwest::get(url).await?;
    let response: PriceResponse = res.json().await?;
    
    // 测试读取:打印ID为4151的物品(龙战靴)价格信息
    if let Some(item_price) = response.data.get(&4151) {
        println!("龙战靴最新交易数据:{:?}", item_price);
    }
    Ok(())
}

补充说明:serde默认支持驼峰命名字段匹配,不需要额外添加#[serde(rename_all = "camelCase")]配置即可正常解析接口返回的highTime/lowTime字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 19:09:52