Reqwest для Rust: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Reqwest и зачем он нужен?

Reqwest — это одна из самых популярных и удобных библиотек для выполнения HTTP-запросов на языке Rust. Она предоставляет эргономичный, высокоуровневый API, построенный на базе асинхронного HTTP-движка hyper и tokio. Если вы пишете на Rust веб-скрапер, клиент для REST API, бота для Telegram или просто хотите скачать файл — Reqwest станет вашим основным инструментом.

Библиотека поддерживает как асинхронные (по умолчанию), так и синхронные (блокирующие) запросы, работу с JSON, multipart/form-data, куки, прокси, TLS/SSL, перенаправления и многое другое. Reqwest спроектирован так, чтобы быть интуитивно понятным для разработчиков, знакомых с Python-библиотекой requests или JavaScript-библиотекой fetch.

Ключевые возможности:

  • Асинхронные и синхронные HTTP/HTTPS запросы (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)
  • Автоматическая сериализация и десериализация JSON (через serde)
  • Поддержка multipart/form-data для загрузки файлов
  • Управление куками (Cookie Store)
  • Поддержка прокси (HTTP, HTTPS, SOCKS5)
  • Кастомизация таймаутов, заголовков, User-Agent
  • Работа с потоками (streaming) для больших ответов
  • Безопасность по умолчанию (проверка SSL-сертификатов)

Установка

Для использования Reqwest вам потребуется проект на Rust с Cargo.toml. Добавьте зависимость в раздел [dependencies]:

[dependencies]
reqwest = { version = "0.12", features = ["json", "multipart", "cookies", "socks"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

Пояснение к features:

  • json — включает поддержку сериализации/десериализации JSON через serde.
  • multipart — для отправки multipart/form-data.
  • cookies — для автоматического управления куками.
  • socks — для поддержки SOCKS5 прокси.
  • Если вам нужен только синхронный (блокирующий) клиент, добавьте feature blocking.

Для синхронного использования (без асинхронности) можно подключить так:

reqwest = { version = "0.12", features = ["blocking", "json"] }

Быстрый старт с примером кода

Давайте сделаем простой GET-запрос к публичному API и выведем результат. Создайте файл main.rs:

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Выполняем GET запрос
    let response = reqwest::get("https://api.github.com/repos/rust-lang/rust")
        .await?;

    // Проверяем статус
    if response.status().is_success() {
        // Парсим тело ответа как JSON (без строгой типизации)
        let body: serde_json::Value = response.json().await?;
        println!("Название репозитория: {}", body["full_name"]);
        println!("Описание: {}", body["description"].as_str().unwrap_or("Нет описания"));
        println!("Звезд: {}", body["stargazers_count"]);
    } else {
        eprintln!("Ошибка: {}", response.status());
    }

    Ok(())
}

Запустите командой cargo run. Вы должны увидеть информацию о репозитории Rust.

Основные методы и функции

1. reqwest::get()

Что делает: Выполняет HTTP GET-запрос по указанному URL. Это самый простой способ получить данные. Возвращает Response.

Параметры:

  • url: impl IntoUrl — строка или URL, куда отправляется запрос.

Пример:

let resp = reqwest::get("https://httpbin.org/get").await?;
println!("Статус: {}", resp.status());

2. Client::new() и Client::get()

Что делает: Создает экземпляр HTTP-клиента с общими настройками (таймауты, заголовки, куки). Рекомендуется переиспользовать один клиент для всех запросов. Client::get() создает построитель запроса (RequestBuilder).

Параметры (для Client::new):

  • Нет обязательных. Можно настроить через Client::builder().

Пример:

let client = reqwest::Client::new();
let resp = client.get("https://api.example.com/data")
    .header("User-Agent", "MyApp/1.0")
    .send()
    .await?;

3. RequestBuilder::send()

Что делает: Отправляет сконфигурированный запрос и возвращает Response. Это финальный шаг после настройки метода, заголовков, тела и т.д.

Параметры: Нет (метод вызывается на построителе).

Пример:

let resp = client.post("https://httpbin.org/post")
    .body("some data")
    .send()
    .await?;

4. Response::json<T>()

Что делает: Асинхронно читает все тело ответа и десериализует его из JSON в указанный тип T. Требует, чтобы T реализовывал трейт serde::Deserialize.

Параметры:

  • Тип T — структура, в которую нужно десериализовать JSON.

Пример:

#[derive(Deserialize, Debug)]
struct User {
    id: u32,
    name: String,
    email: String,
}

let user: User = resp.json().await?;
println!("{:?}", user);

5. Response::text()

Что делает: Асинхронно читает все тело ответа как строку (String). Полезно для HTML, XML или текстовых ответов.

Параметры: Нет.

Пример:

let body_text = resp.text().await?;
println!("{}", &body_text[..200]); // Вывести первые 200 символов

6. RequestBuilder::json()

Что делает: Устанавливает тело запроса, сериализуя переданное значение в JSON. Автоматически устанавливает заголовок Content-Type: application/json.

Параметры:

  • value: &T — ссылка на данные, которые нужно сериализовать. T должен реализовывать serde::Serialize.

Пример:

#[derive(Serialize)]
struct LoginRequest {
    username: String,
    password: String,
}

let login = LoginRequest {
    username: "admin".into(),
    password: "secret".into(),
};

let resp = client.post("https://api.example.com/login")
    .json(&login)
    .send()
    .await?;

7. RequestBuilder::multipart()

Что делает: Устанавливает тело запроса в формате multipart/form-data. Используется для загрузки файлов и отправки форм с несколькими частями.

Параметры:

  • form: reqwest::multipart::Form — сконструированный объект формы.

Пример:

use reqwest::multipart;

let form = multipart::Form::new()
    .text("username", "rust_user")
    .file("avatar", "/path/to/avatar.png").await?;

let resp = client.post("https://api.example.com/upload")
    .multipart(form)
    .send()
    .await?;

8. RequestBuilder::header()

Что делает: Добавляет или перезаписывает HTTP-заголовок в запросе.

Параметры:

  • key: HeaderName — имя заголовка (например, "Authorization").
  • value: HeaderValue — значение заголовка (строка).

Пример:

let resp = client.get("https://api.github.com/user")
    .header("Authorization", "Bearer YOUR_TOKEN")
    .header("User-Agent", "MyRustApp")
    .send()
    .await?;

9. Client::builder() и настройки

Что делает: Создает построитель для тонкой настройки клиента перед его созданием. Позволяет установить таймауты, прокси, куки-хранилище, пользовательский агент по умолчанию и т.д.

Параметры: Нет (возвращает ClientBuilder).

Пример:

let client = reqwest::Client::builder()
    .timeout(std::time::Duration::from_secs(30))
    .user_agent("MyApp/1.0")
    .cookie_store(true)
    .proxy(reqwest::Proxy::https("https://proxy.example.com:8080")?)
    .build()?;

let resp = client.get("https://httpbin.org/cookies/set?name=value")
    .send()
    .await?;

10. Response::error_for_status()

Что делает: Проверяет статус ответа. Если статус — ошибка (4xx или 5xx), возвращает Err с соответствующим сообщением. Удобно для валидации.

Параметры: Нет.

Пример:

let resp = client.get("https://httpbin.org/status/404")
    .send()
    .await?;

// Если статус не 2xx, программа завершится с ошибкой
let resp = resp.error_for_status()?;
println!("Успех: {}", resp.status());

11. RequestBuilder::query()

Что делает: Добавляет параметры строки запроса (query string) к URL. Принимает слайс пар ключ-значение или ссылку на структуру, реализующую Serialize.

Параметры:

  • params: &[(&str, &str)] или сериализуемый объект.

Пример:

let resp = client.get("https://api.github.com/search/repositories")
    .query(&[("q", "rust"), ("sort", "stars")])
    .send()
    .await?;

// Или с использованием структуры:
#[derive(Serialize)]
struct SearchParams {
    q: String,
    sort: String,
}
let params = SearchParams { q: "rust".into(), sort: "stars".into() };
let resp = client.get("https://api.github.com/search/repositories")
    .query(¶ms)
    .send()
    .await?;

Реальный практический пример использования

Давайте напишем полноценный скрипт, который авторизуется на фейковом API, получает список задач (todos) и выводит только невыполненные. Мы используем jsonplaceholder.typicode.com

Рекомендаций