如何修复 reqwest 的 JSON 解码错误?

4
当我运行以下代码时:
use exitfailure::ExitFailure;
use reqwest::Url;
use serde_derive::{Deserialize, Serialize};
use std::env;

#[derive(Serialize, Deserialize, Debug)]
struct CompanyInfo {
    country: String,
    currency: String,
    exchange: String,
    ipo: String,
    marketCapitalization: u128,
    name: String,
    phone: String,
    shareOutstanding: f64,
    ticker: String,
    weburl: String,
    logo: String,
    finnhubIndustry: String,
}

impl CompanyInfo {
    async fn get(symbol: &String, api_key: &String) -> Result<Self, ExitFailure> {
        let url = format!(
            "https://finnhub.io/api/v1/stock/profile2?symbol={}&token={}",
            symbol, api_key
        );

        let url = Url::parse(&*url)?;
        let res = reqwest::get(url).await?.json::<CompanyInfo>().await?;

        Ok(res)
    }
}

#[tokio::main]
async fn main() -> Result<(), ExitFailure> {
    let api_key = "MY API KEY".to_string();
    let args: Vec<String> = env::args().collect();
    let mut symbol: String = "AAPL".to_string();

    if args.len() < 2 {
        println!("Since you didn't specify a company symbol, it has defaulted to AAPL.");
    } else {
        symbol = args[1].clone();
    }

    let res = CompanyInfo::get(&symbol, &api_key).await;
    println!("{:?}", res);

    Ok(())
}

我遇到了一个错误: Err(error decoding response body: expected ',' or '}' at line 1 column 235)。在另一个API中,具有类似结构的代码可以正常工作。您如何使用reqwest解决此问题?


1
如何解决reqwest的问题?实际上你并不需要,因为问题似乎出在API方面。如果响应无效(根据错误信息),那么reqwest无能为力。你应该单独获取响应(例如通过curl/wget)并确认它始终是一个正确和完整的JSON。请注意,某些API在错误时不返回JSON文档(非200响应)。如果这种情况发生在这里,你将需要先处理HTTP错误情况,只有当你知道已获得成功响应后才尝试对其进行解码。 - Masklinn
1个回答

10
通常,“error decoding response body”意味着您尝试反序列化一个特定格式的HTTP响应,但是响应实体不符合该格式。在您的情况下,您正在尝试反序列化JSON,因此错误意味着您尝试反序列化的内容可能不是有效的JSON,或者它是有效的JSON,但您期望的JSON结构与服务器返回的结构不匹配。服务器可能在创建其JSON时出了问题,或者它返回的响应实体实际上不是JSON,有特定原因(例如,某些API在返回500响应时不会返回JSON)。
为了调试和修复此问题,您需要确切地了解要解析的响应实体的样子。一种方法是将代码的解析拆分为两部分:一个获取文本的部分,另一个尝试解析的部分。例如,为了调试目的,您可以打印出接收到的响应,如下所示:
// Split up the JSON decoding into two steps.
// 1.) Get the text of the body.
let response_body = reqwest::get(url).await?.text().await?;
println!("Response Body: {}", response_body);

// 2.) Parse the results as JSON.
let res: CompanyInfo = serde_json::from_str(&response_body)?;

这段代码可能仍然会失败,但现在你将看到失败的响应体被打印出来。在那时,你需要分析响应体,这时它将有望变得更加明显为什么它不起作用。


我得到了这个:响应正文:{"country":"US","currency":"USD","exchange":"纳斯达克NMS-全球市场","finnhubIndustry":"","ipo":"2010-06-29","logo":"https://static.finnhub.io/logo/2dd96524-80c9-11ea-aaac-00000000092a.png","marketCapitalization":783117.67,"name":"特斯拉公司","phone":"16506815000.0","shareOutstanding":905,"ticker":"TSLA","weburl":"https://www.tesla.com/"} - Henry Boisdequin
看起来它是有效的 JSON,但仍然在 JSON 解析时出错。 - Henry Boisdequin
1
@HenryBoisdequin 这是有效的JSON,但不适用于您的结构。您的结构包括一个marketCapitalization字段,而您展示的响应中没有该字段。由于缺少该字段,无法完全反序列化CompanyInfo结构,因此出现了错误。我通过在Rust Playground上运行此代码来找出这个问题,并显示了完整的错误信息:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=af20de9b3f6eda2a10f5f8f1780d8ab2 - Mark Hildreth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接