Rust 每日一庫之 reqwest

關注「Rust 編程指北」,一起學習 Rust,給未來投資

大家好,我是螃蟹哥。

今天給大家推薦一個 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::<Response>().await?;) 調用 json(),如下所示:

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

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

#[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::<Response>().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

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/eW0qY49F6lSRvGqYDqL1PA