Что такое 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