反序列化 reqwest::Reponse 为 JSON,但在出错时打印响应文本

Flo*_*ker 5 ownership rust serde reqwest

我正在将 a 解码reqwest::Response为 JSON。通常这工作正常,但在极少数情况下,远程服务器返回的响应不适合我struct用于反序列化的响应。在这些情况下,我想打印出原始响应文本以进行进一步调试。

但是,我在执行 JSON 反序列化打印响应正文时遇到了麻烦。我想做的是

#[derive(serde::Deserialize)]
struct MyData {
    // ...
}

async fn get_json(url: &str) -> Result<MyData, reqwest::Error> {
    let response = reqwest::get(url).await?;
    let text = response.text().await?;
    response
        .json::<MyData>().await
        .map_err(|err| {
            println!(
                "Could not decode response from {}: {}", url, text
            );
            err
        })
}
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为response.text需要self,所以我不能重复使用responsefor response.json

基于另一个答案的代码(也在这个答案中推荐)我发现了这种方法:

let response = reqwest::get(url).await?;
let text = response.text().await?;
serde_json::from_str(&text).map_err(...)
Run Code Online (Sandbox Code Playgroud)

但是,serde_json::from_str返回 a Result<_, serde_json::Error>,因此这种方法会使我的错误处理复杂化,因为所有调用之前都返回Result<_, reqwest::Error>. 我希望我的函数也返回后者,而不是一些自定义错误包装器。

实现我的目标的惯用方法是什么?

Pat*_*ick 1

我不认为你会逃避.text()然后serde_json::from_str(&text)分手。

但是您可以避免使用该anyhow库来定义自定义错误类型(正如 kmdreko 在他/她的评论中建议的那样)。只需使用Result<T, anyhow::Error>或等效的anyhow::Result<T>,作为任何易出错函数的返回类型。

例如(从我的代码库复制):

use anyhow::{Context, Result};
use reqwest::Client;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use url::Url;

#[derive(Debug)]
pub struct UrlPath<'a>(&'a str);

pub async fn get<T: DeserializeOwned>(
    client: &Client,
    backend_url: &Url,
    path: &UrlPath<'_>,
) -> Result<T> {
    let response = client
        .get(backend_url.join(path.0).with_context(|| {
            format!(
                "Unable to join base URL \"{}\" with path \"{:?}\"",
                backend_url, path
            )
        })?)
        .send()
        .await?;

    let contents = response.text().await?;
    serde_json::from_str(&contents).with_context(|| {
        format!("Unable to deserialise response. Body was: \"{}\"", contents)
    })
}
Run Code Online (Sandbox Code Playgroud)

这会给你一个很好的错误,如下所示:

Error: Unable to fetch Source Kinds

Caused by:
    0: Unable to deserialise response. Body was: "{"detail":"Authentication credentials were not provided."}"
    1: invalid type: map, expected a sequence at line 1 column 0

Run Code Online (Sandbox Code Playgroud)

with_context()fromanyhow允许您为错误提供自定义上下文。并将anywhow转换大多数错误,使它们“正常工作”。

但仅将其用于应用程序代码,您不需要告诉调用者到底出了什么问题。

更多信息: https: //docs.rs/anyhow/latest/anyhow/index.html