rust - 解开 reqwest::get.text 结果的优雅方法

标签 rust reqwest

我需要使用 reqwest::get 从 API 读取简单的文本数据,因此我实现了以下内容:

#[tokio::main]
async fn process_api() {
    let response_text = reqwest::get("https://httpbin.org/anything")
        .await.unwrap().text()
        .await.unwrap();
    println!("{}", response_text);
}

根据文档

Because this function may panic, its use is generally discouraged.

因此,我决定用更安全的变体重写它,以显式处理错误情况:

#[tokio::main]
async fn process_api() {
    let response = reqwest::get("https://httpbin.org/anything").await;
    match response {
        Ok(resp) => {
            match resp.text().await {
                Ok(response_text) => {
                    println!("{}", response_text);
                }
                Err(e) => {
                    println!("Error with API while fetching text {}", e)
                }
            }
        }
        Err(e) => {
            println!("Error with API {}", e)
        }
    }
}

但是那段代码看起来太冗长了 我还尝试了 if let 构造:

#[tokio::main]
async fn process_api() {
    let response = reqwest::get("https://httpbin.org/anything").await;
    if let Ok(resp) = response {
        if let Ok(response_text) = resp.text().await {
            println!("{}", response_text);
        } else {
            println!("Error with API while fetching text!")
        }
    } else {
        println!("Error with API");
    }
}

但即使它看起来更短,日志中也不会出现Error。因此,在这种特殊情况下,情况似乎更糟。

我的问题 - 有更好的方法来写这个吗?

请注意,我不想一直 panic main,而是优雅地记录潜在的错误。

老实说,我尝试了 map*/and_then 的不同变体,我得到的“最好的”是:

#[tokio::main]
async fn process_api() {
    let response = reqwest::get("https://httpbin.org/anything").await;
    response
        .map(|resp| async move {
            match resp.text().await {
                Ok(response_text) => {
                    println!("{}", response_text);
                }
                Err(e) => {
                    println!("Error with API {}", e)
                }
            }
        }).unwrap().await;
}

但它看起来很可怕。

最佳答案

更改process_response以返回Result,然后您可以使用? operator处理错误。

async fn process_api() -> reqwest::Result<String> {
    let response_text = reqwest::get("https://httpbin.org/anything")
        .await?
        .text().await?;
    Ok(response_text)
}

#[tokio::main]
async fn main() {
    match process_api().await {
        Ok(response) => println!("{}", response)
        Err(e) => eprintln!("Error in request: {:?}", e)
    }
}

如果您想了解有关错误的更多信息,可以使用 anyhow's context method .

async fn process_api() -> anyhow::Result<String> {
    let response_text = reqwest::get("https://httpbin.org/anything")
        .await.context("Failed get request")?
        .text().await.connext("Failed to get text body")?;
    Ok(response_text)
}

关于rust - 解开 reqwest::get.text 结果的优雅方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75065308/

相关文章:

rust - 在 Rust 中实现 Index 和 IndexMut 时如何避免冗余代码

select - 结合使用 Rust 库 reqwest 和 select

rust - 如何使用流解压缩 Reqwest/Hyper 响应?

ssl - 为什么 reqwest 需要安装 OpenSSL?

http - 为什么来自 api.color.pizza 的 reqwest 响应会返回意外的字节?

rust - 是 Rust 中的外部 crate 序列影响吗

rust - 在 Rust 中指定数组大小时,C 的 #define 等效于什么?

rust - 取消引用 *mut T 转换为 *mut ManuallyDrop<T> 是未定义的行为吗?

rust - 将枚举转换为 BTreeMap?