使用 Rust 發送 HTTP 請求

前言

一般情境下,可以使用 reqwest 套件來發送 HTTP 請求,它是基於提供低階 API 的 hyper 套件的封裝。

做法

使用 reqwest 套件

安裝依賴套件。

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

GET

修改 main.rs 檔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use serde::{Deserialize, Serialize};
use std::error::Error;

#[derive(Serialize, Deserialize, Debug)]
struct Response {
origin: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let resp = fetch().await?;
println!("{:#?}", resp);
Ok(())
}

async fn fetch() -> Result<Response, Box<dyn Error>> {
let client = reqwest::Client::new();
let res = client
.get("https://httpbin.org/ip")
.send()
.await?
.json::<Response>()
.await?;
return Ok(res);
}

執行程式。

1
cargo run

輸出如下:

1
2
3
Response {
origin: "101.10.97.155",
}

POST

修改 main.rs 檔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, error::Error};

#[derive(Serialize, Deserialize, Debug)]
struct Response {
json: HashMap<String, String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let resp = fetch().await?;
println!("{:#?}", resp);
Ok(())
}

async fn fetch() -> Result<Response, Box<dyn Error>> {
let mut map = HashMap::new();
map.insert("lang", "rust");
map.insert("body", "json");
let client = reqwest::Client::new();
let res = client
.post("https://httpbin.org/anything")
.json(&map)
.send()
.await?
.json::<Response>()
.await?;
return Ok(res);
}

執行程式。

1
cargo run

輸出如下:

1
2
3
4
5
6
Response {
json: {
"lang": "rust",
"body": "json",
},
}

使用 hyper 套件

安裝依賴套件。

1
2
3
[dependencies]
hyper = { version = "0.14", features = ["full"] }
tokio = { version = "1", features = ["full"] }

修改 main.rs 檔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use hyper::{Client, Uri};
use std::str;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new();
let uri = Uri::from_static("http://httpbin.org/ip");
let mut res = client.get(uri).await?;

println!("status code: {}", res.status());
for (key, value) in res.headers().iter() {
println!("{}: {}", key, value.to_str().unwrap())
}

let body = res.body_mut();
let buf = hyper::body::to_bytes(body).await?;
let content = str::from_utf8(buf.as_ref())?;
println!("{}", content);

Ok(())
}

執行程式。

1
cargo run

輸出如下:

1
2
3
4
5
6
7
8
9
10
11
status code: 200 OK
date: Mon, 05 Dec 2022 15:09:59 GMT
content-type: application/json
content-length: 32
connection: keep-alive
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true
{
"origin": "101.10.97.155"
}

參考資料