Rust 每日一库之 reqwest

polarisxu

共 4281字,需浏览 9分钟

 · 2021-10-11

今天给大家推荐一个 crate 的使用:reqwest,主要介绍如何使用 reqwest crate 与 Rust 中的 HTTP API 交互。从通过序列化、代理和自定义头的简单 HTTP 请求开始。

作为 Rust 之旅的一部分,我正在构建一个简单的 CLI 来解决我必须定期完成的手动任务。其中一些任务可以通过利用 Rust 中的 HTTP 客户端来自动化。一项快速的研究让我找到了reqwest[1],这是一个简单的 Rust HTTP 客户端,满足我的需求,让我快速完成工作。

你可能会问 reqwest是不是 Rust最佳 HTTP 客户端? 老实说,我不知道。但是我用它很快就完成了我的工作,而且我真的很喜欢reqwest。让我们深入了解 reqwest

01 安装 reqwest

你可以通过将它加入 Cargo.toml 这种方式简单快速安装 reqwest,同时把 tokio 也添加并安装,因为 reqwest 底层使用了这个异步运行时。

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

虽然reqwest可以使用不同的Content-Types,但这篇文章侧重于处理 JSON,因为我处理的大多数 HTTP API 都以这种特定格式返回数据。

02 使用 reqwest 的简单 GET 请求

让我们发出一个简单的 GET 请求来查看 HTTP 调用的reqwest实际情况。

let b = reqwest::get("https://swapi.dev/api/people")
    .await?
    .json()
    .await?;

println!("Got {:?}", b);

本示例使用简便的方法 get 快速发出简单的 HTTP GET 请求。很有可能,你会在应用程序中发出许多不同的请求。如果是这种情况,你应该考虑创建一个专用的Client并将其重用于多个独立的 HTTP 请求。

03 reqwest 中的 Client 和 RequestBuilder

通过使用专用Client,你可以快速创建不同类型的新请求。Client提供诸如 get, post, put, delete ... 之类的方法,以及 request(&self, method: Method, url: U) 可用于创建新RequestBuilderRequestBuilder 在发出某个请求之前,你可以自定义它的所有方面。RequestBuilder 提供的功能被设计为链式(或流畅的)API。例如,考虑以下 GET 请求,它在发出请求之前添加额外的 HTTP 头并指定自定义超时:

use reqwest;
use std::error::Error;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let client = reqwest::Client::new();
    let doge = client
        .get("https://api.coinstats.app/public/v1/coins/dogecoin")
        .header("Accept""text/plain")
        .timeout(Duration::from_secs(3))
        .send()
        .await?
        .text()
        .await?;
    println!("{:}", doge);
    Ok(())
}

04 默认 HTTP 头

在前面的示例中,RequestBuilder 使用 header 函数设置 HTTP 头:Accept。你还可以使用ClientBuilder为发出的所有请求指定 HTTP 头:

use reqwest;
use reqwest::header;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let mut h = header::HeaderMap::new();
    h.insert("Accept", header::HeaderValue::from_static("application/json"));
    
    let client = reqwest::Client::builder()
        .default_headers(h)
        .build()?;

    let doge = client
        .get("https://api.coinstats.app/public/v1/coins/dogecoin")
        .send()
        .await?
        .text()
        .await?;
    println!("{:}", doge);
    Ok(())
}

05 使用 reqwest 解压 GZIP 响应

当 API 返回的数据使用了 GZIP 压缩时,你可以即时解压缩。这需要 reqwest 启用 gzip 功能(在 Cargo.toml 中配置)。GZIP 通过调用以下 gzip 函数启用自动解压缩ClientBuilder

// omitted
let client = reqwest::Client::builder()
    .gzip(true)
    .default_headers(h)
    .build()?;
// omitted

如果服务器将 Content-Encoding: gzip HTTP 头作为 HTTP 响应的一部分发送,则响应正文将自动解压缩。

06 反序列化 JSON 响应正文

要将响应反序列化为 struct,请将 serde 添加到 Cargo.toml

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

显然,你必须在 Rust 中重新创建响应结构,并使用 Response.json() 。你可以显式提供所需变量的类型 ( let p: Response = r::json().await?;) ,或者使用 turbo-fish 语法 ( let p = r.json::().await?;) 调用 json(),如下所示:

use std::error::Error;
use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct Response {
    coins: Vec,
}

#[derive(Deserialize, Debug)]
struct Coin {
    id: String,
    name: String,
    icon: String,
    symbol: String,
    price: f32,
    priceBtc: f32,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let http_response = reqwest::get("https://api.coinstats.app/public/v1/coins?skip=0&limit=10").await?;
    let response = http_response.json::().await?;
    println!("{:#?}", response.coins);
    Ok(())
}

07 使用 reqwest 的自定义 HTTP 代理

reqwest 默认情况下可以使用 HTTP 代理。如果设置,HTTP 代理 URL 将自动从 HTTP_PROXYHTTPS_PROXY 环境变量加载。你还可以使用 Proxy 如下所示的结构覆盖这些设置:

// omitted
let client = reqwest::Client::builder()
    .proxy(reqwest::Proxy::https("https://my-proxy.local")
    .build()?;
// omitted

你可以在 ClientBuilder 上调用 no_proxy() 来禁用代理:

// omitted
let client = reqwest::Client::builder()
    .no_proxy()
    .build()?;
// omitted

08 结论

使用 reqwest,我可以轻松地与 HTTP API 交互。它只是另一个 HTTP 客户端库,这里没什么特别的 。它满足我的要求。我喜欢流畅的 API 设计,它可以让我快速调用给定的 HTTP(s) API。也就是说,reqwest 值得一看。

参考资料

[1]

reqwest: https://github.com/seanmonstar/reqwest




推荐阅读

我是 polarisxu,北大硕士毕业,曾在 360 等知名互联网公司工作,10多年技术研发与架构经验!2012 年接触 Go 语言并创建了 Go 语言中文网!著有《Go语言编程之旅》、开源图书《Go语言标准库》等。


坚持输出技术(包括 Go、Rust 等技术)、职场心得和创业感悟!欢迎关注「polarisxu」一起成长!也欢迎加我微信好友交流:gopherstudio


浏览 677
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报