Как выполнить HTTP-запрос на Rust? Нет встроенной функции?
Как выполнить HTTP-запрос на Rust: современный подход
Вы правы — в стандартной библиотеке Rust нет встроенного HTTP-клиента. Это осознанное решение разработчиков языка: стандартная библиотека должна быть минимальной и стабильной, а HTTP-клиенты быстро развиваются. Лучший способ — использовать крейт reqwest. Он поддерживает и синхронные, и асинхронные запросы, автоматически обрабатывает перенаправления, сжатие и TLS.
Установка
Добавьте в Cargo.toml:
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
Простой синхронный GET-запрос
Если вам не нужна асинхронность, используйте блокирующий клиент:
use reqwest::blocking::Client;
fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let response = client
.get("https://api.github.com/repos/rust-lang/rust")
.header("User-Agent", "my-rust-app")
.send()?;
println!("Статус: {}", response.status());
println!("Заголовки: {:?}", response.headers());
let body = response.text()?;
println!("Тело ответа: {}", body);
Ok(())
}
Асинхронный GET-запрос (рекомендуемый способ)
Современный Rust активно использует асинхронность. Вот пример с async/await:
use reqwest::Client;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new();
let response = client
.get("https://jsonplaceholder.typicode.com/posts/1")
.send()
.await?;
let json: serde_json::Value = response.json().await?;
println!("ID: {}", json["id"]);
println!("Заголовок: {}", json["title"]);
Ok(())
}
POST-запрос с JSON
use reqwest::Client;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let payload = json!({
"title": "foo",
"body": "bar",
"userId": 1
});
let response = client
.post("https://jsonplaceholder.typicode.com/posts")
.json(&payload)
.send()
.await?;
println!("Создан: {:?}", response.text().await?);
Ok(())
}
Обработка ошибок
Всегда проверяйте статус ответа:
let response = client.get(url).send().await?;
if response.status().is_success() {
let data = response.text().await?;
// обрабатываем данные
} else {
eprintln!("Ошибка: {}", response.status());
}
Почему не TcpStream напрямую?
- HTTP — сложный протокол: требует парсинга заголовков, обработки chunked encoding, поддержки HTTPS (TLS).
reqwestделает это за вас, включая автоматическое управление keep-alive соединениями.- Безопасность:
reqwestиспользуетrustlsилиnative-tlsдля HTTPS.
Альтернативы
ureq— минималистичный синхронный клиент без зависимостей от Tokio. Хорош для простых скриптов.hyper— низкоуровневая библиотека, на которой построенreqwest. Используйте, если нужен полный контроль.
Начните с reqwest — это стандарт де-факто для HTTP-запросов в Rust. Он активно поддерживается и имеет отличную документацию.
Альтернативный подход: синхронный клиент ureq
Если вы не хотите связываться с асинхронностью и Tokio, отличный выбор — крейт ureq. Он полностью синхронный, не требует настройки рантайма и идеально подходит для простых скриптов, утилит или когда асинхронность избыточна.
Установка
[dependencies]
ureq = { version = "2.10", features = ["json"] }
Пример GET-запроса
use ureq;
fn main() -> Result<(), ureq::Error> {
let response = ureq::get("https://api.github.com/repos/rust-lang/rust")
.set("User-Agent", "my-app")
.call()?;
let body: String = response.into_string()?;
println!("{}", body);
Ok(())
}
POST с JSON
use ureq::json;
fn main() -> Result<(), ureq::Error> {
let payload = json!({
"title": "Пример",
"body": "Тело запроса"
});
let response = ureq::post("https://httpbin.org/post")
.send_json(payload)?;
println!("Ответ: {}", response.into_string()?);
Ok(())
}
Когда использовать ureq вместо reqwest?
- Вам нужен простой скрипт без асинхронности.
- Вы не хотите подключать Tokio (экономия времени компиляции).
- Вы пишете библиотеку, которая не должна диктовать пользователю выбор рантайма.
ureq поддерживает HTTPS, куки, перенаправления и JSON. Для большинства задач его функциональности достаточно. Если позже понадобится асинхронность, легко перейти на reqwest — API очень похожи.