HTTP-клиент для Rust: обзор лучших библиотек
Rust — язык системного программирования, который всё чаще используется для создания веб-сервисов, микросервисов и инструментов для работы с сетью. Выбор правильного HTTP-клиента критически важен для производительности, безопасности и удобства разработки. В этой статье мы рассмотрим три наиболее популярные библиотеки для выполнения HTTP-запросов в экосистеме Rust: reqwest, ureq и hyper. Каждая из них имеет свои сильные стороны и подходит для разных сценариев.
1. Reqwest — универсальный выбор
Reqwest — это, пожалуй, самая популярная библиотека для HTTP-запросов в Rust. Она построена на основе hyper и предоставляет высокоуровневый, эргономичный API. Поддерживает как асинхронные (через tokio), так и синхронные запросы (с включением соответствующего флага).
Ключевые особенности:
- Асинхронный и синхронный режимы.
- Автоматическая обработка перенаправлений.
- Работа с JSON (сериализация/десериализация через
serde). - Поддержка cookies, прокси, TLS.
- Удобная работа с формами и multipart-данными.
Пример асинхронного GET-запроса:
use reqwest;
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct ApiResponse {
userId: u32,
id: u32,
title: String,
completed: bool,
}
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let url = "https://jsonplaceholder.typicode.com/todos/1";
let response: ApiResponse = reqwest::get(url)
.await?
.json()
.await?;
println!("{:#?}", response);
Ok(())
}
Этот пример показывает, как легко выполнить GET-запрос и десериализовать JSON-ответ в структуру. Reqwest идеально подходит для большинства проектов: от простых скриптов до крупных веб-приложений.
2. Ureq — минимализм и простота
Ureq — это лёгкий, синхронный HTTP-клиент. Его главное преимущество — минимальное количество зависимостей и отсутствие необходимости в асинхронном рантайме. Вы просто добавляете крейт и используете его. Отлично подходит для CLI-утилит, скриптов и ситуаций, где не нужна асинхронность.
Ключевые особенности:
- Полностью синхронный (блокирующий) API.
- Минимальное количество зависимостей (не требует
tokio). - Встроенная поддержка JSON и cookie.
- Простая работа с заголовками и параметрами.
Пример POST-запроса с JSON:
use ureq;
use serde::Serialize;
#[derive(Serialize)]
struct NewTodo {
title: String,
completed: bool,
}
fn main() -> Result<(), ureq::Error> {
let todo = NewTodo {
title: "Изучить Rust".into(),
completed: false,
};
let response = ureq::post("https://jsonplaceholder.typicode.com/todos")
.set("Content-Type", "application/json")
.send_json(&todo)?;
let status = response.status();
let body = response.into_string()?;
println!("Status: {}, Body: {}", status, body);
Ok(())
}
Ureq прощает ошибки новичкам и позволяет быстро прототипировать. Однако он не подходит для высоконагруженных асинхронных систем.
3. Hyper — фундамент экосистемы
Hyper — это низкоуровневая, асинхронная библиотека, на которой построены reqwest и многие другие крейты. Она даёт полный контроль над HTTP-соединением, но требует больше кода и понимания асинхронного программирования. Используется в production-системах, где критична производительность (например, в базах данных или прокси-серверах).
Ключевые особенности:
- Асинхронность на базе
tokio. - Полный контроль над каждым аспектом запроса.
- Поддержка HTTP/1.x и HTTP/2.
- Используется как основа для других библиотек.
- Требует ручного управления соединениями и телом запроса.
Пример простого GET-запроса с Hyper:
use hyper::{Client, Uri};
use hyper::body::HttpBody;
use tokio::io::{stdout, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box