🎓 A1Learner
🔍

Rust HTTP Requests

An HTTP request asks a server for a page or for data. The reqwest crate makes HTTP requests in Rust, with a blocking feature that needs no async.

Ask for a page

blocking::get is the one-line request. The answer carries a status:

let response = reqwest::blocking::get("https://example.com").unwrap();
println!("status = {}", response.status());

Read the body as text

let body = reqwest::blocking::get("https://example.com").unwrap().text().unwrap();
println!("mentions Example Domain = {}", body.contains("Example Domain"));
println!("starts with doctype = {}", body.trim_start().starts_with("<!doctype html>"));

A missing page is not a crash

let response = reqwest::blocking::get("https://example.com/no-such-page-12345").unwrap();
println!("status = {}", response.status());
println!("error_for_status fails = {}", response.error_for_status().is_err());

Pairs and a header

A Client request can carry query pairs and headers. The final URL shows the pairs in place:

let client = reqwest::blocking::Client::new();
let response = client
    .get("https://example.com/search")
    .query(&[("q", "rust"), ("page", "2")])
    .header("X-Tool", "link-checker")
    .send()
    .unwrap();
println!("final url = {}", response.url());

Check a page exists

head() fetches headers only. is_success() is true for 2xx statuses:

let client = reqwest::blocking::Client::new();
let here = client.head("https://example.com").send().unwrap();
let gone = client.head("https://example.com/no-such-page-12345").send().unwrap();
println!("home exists = {}", here.status().is_success());
println!("missing page exists = {}", gone.status().is_success());

Example

use reqwest::blocking::Client;

fn main() {
    let client = Client::new();

    let home = client.get("https://example.com").send().unwrap();
    println!("home status = {}", home.status());
    let body = home.text().unwrap();
    println!("home is the Example Domain page = {}", body.contains("Example Domain"));

    let missing = client.head("https://example.com/no-such-page-12345").send().unwrap();
    println!("missing page status = {}", missing.status());
    println!("missing counted as success = {}", missing.status().is_success());
}

Key points

  • Add reqwest = { version = "0.12", features = ["blocking"] } to Cargo.toml.
  • An Ok response only means the server answered.
  • A 404 page is a successful request with a sad status.
  • It is not an Err.
  • error_for_status() turns a bad status into an Err when you would rather handle all failures in one place
  • Build one Client and reuse it for many requests.
  • It keeps connections open between calls.
  • That is faster than starting fresh each time.
  • A HEAD request asks for the headers only, with no body: the cheap way to check that a page exists
  • One reqwest call asks the server and waits for its answer.

In this example, a small site checker uses one Client for both jobs. The GET request fetches the home page: status 200 OK, and the body really is the Example Domain page. The HEAD request then probes a made-up address: the server answers 404 Not Found, and is_success() reports false. Notice that neither request produced an Err. Reaching the server is success. The status tells you what the server thought of the address. reqwest also has an async side that runs on Tokio — the same requests, written with .await (see the Tokio lessons)

Note

These examples fetch example.com, the test page the internet keeps for exactly this purpose.

It never changes, so the outputs below are stable.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

A GET request returns a response with status 404. What did the request return?