Что такое Hyper и зачем он нужен
Hyper — это высокопроизводительная асинхронная HTTP-библиотека для языка Rust, написанная на самом Rust. Она является одной из самых популярных и уважаемых библиотек в экосистеме Rust для работы с HTTP/1 и HTTP/2 протоколами. Hyper предоставляет как клиентскую, так и серверную части, позволяя разработчикам создавать быстрые, безопасные и эффективные веб-приложения и API.
Основные причины использовать Hyper:
- Производительность: Hyper построен на асинхронном рантайме Tokio и использует неблокирующий ввод-вывод, что позволяет обрабатывать тысячи одновременных соединений с минимальным потреблением ресурсов.
- Безопасность: Rust гарантирует безопасность памяти на этапе компиляции, а Hyper следует этим принципам, минимизируя риски утечек памяти и гонок данных.
- Гибкость: Библиотека предоставляет низкоуровневый контроль над HTTP-соединениями, позволяя реализовать практически любую логику обработки запросов.
- Совместимость: Hyper является основой для многих других популярных Rust-фреймворков, таких как Warp, Axum и Tide.
- Поддержка HTTP/2: Встроенная поддержка HTTP/2 для более эффективного использования сетевых ресурсов.
Hyper идеально подходит для создания микросервисов, прокси-серверов, API-шлюзов и любых других сетевых приложений, где важна скорость и надёжность.
Установка Hyper
Установка Hyper в проект на Rust осуществляется через менеджер пакетов Cargo. Добавьте следующие зависимости в файл Cargo.toml:
[dependencies]
hyper = { version = "1.5", features = ["full"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Объяснение зависимостей:
- hyper: Основная библиотека с включёнными всеми функциями (сервер, клиент, HTTP/2).
- tokio: Асинхронный рантайм, необходимый для работы Hyper.
- serde и serde_json: Для сериализации/десериализации данных (понадобится в примерах).
После добавления зависимостей выполните команду cargo build, чтобы загрузить и скомпилировать библиотеки.
Быстрый старт: простой HTTP-сервер
Создадим минимальный HTTP-сервер, который отвечает "Hello, World!" на любой запрос. Создайте файл src/main.rs со следующим содержимым:
use hyper::service::{service_fn, Service};
use hyper::{Body, Request, Response, Server};
use std::convert::Infallible;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
// Определяем тип для нашего сервиса
struct HelloWorld;
impl Service<Request<Body>> for HelloWorld {
type Response = Response<Body>;
type Error = Infallible;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _req: Request<Body>) -> Self::Future {
let response = Response::builder()
.status(200)
.header("Content-Type", "text/plain")
.body(Body::from("Hello, World!"))
.unwrap();
Box::pin(async { Ok(response) })
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = ([127, 0, 0, 1], 3000).into();
let server = Server::bind(&addr).serve(service_fn(|req| async move {
let response = Response::builder()
.status(200)
.header("Content-Type", "text/plain")
.body(Body::from("Hello, World!"))
.unwrap();
Ok::<_, Infallible>(response)
}));
println!("Сервер запущен на http://{}", addr);
server.await?;
Ok(())
}
Запустите сервер командой cargo run и откройте в браузере http://localhost:3000. Вы увидите сообщение "Hello, World!".
Основные методы и функции Hyper
1. Server::bind
Что делает: Создаёт экземпляр сервера, привязанный к указанному адресу и порту. Это отправная точка для создания HTTP-сервера.
Параметры:
addr: impl Into<SocketAddr>— адрес и порт для прослушивания (например,([127, 0, 0, 1], 3000).into()).
Пример:
use hyper::Server;
let addr = ([127, 0, 0, 1], 8080).into();
let server = Server::bind(&addr);
2. Server::serve
Что делает: Запускает сервер с указанным сервисом (обработчиком запросов). Возвращает Future, который завершается при остановке сервера.
Параметры:
make_service: impl MakeService— фабрика, создающая сервис для каждого нового соединения.
Пример:
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Response, Server};
let make_svc = make_service_fn(|_conn| {
async {
Ok::<_, Infallible>(service_fn(|_req| async {
Ok::<_, Infallible>(Response::new(Body::from("Hello")))
}))
}
});
let server = Server::bind(&addr).serve(make_svc);
3. Response::builder
Что делает: Создаёт конструктор для HTTP-ответа. Позволяет установить статус-код, заголовки и тело ответа.
Параметры: Не принимает параметров, возвращает Builder.
Пример:
use hyper::{Body, Response, StatusCode};
let response = Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/json")
.body(Body::from(r#"{"message": "success"}"#))
.unwrap();
4. Request::builder
Что делает: Создаёт конструктор для HTTP-запроса (обычно используется на стороне клиента). Позволяет задать метод, URI, заголовки и тело.
Параметры: Не принимает параметров, возвращает Builder.
Пример:
use hyper::{Body, Method, Request};
let request = Request::builder()
.method(Method::POST)
.uri("https://api.example.com/data")
.header("Content-Type", "application/json")
.body(Body::from(r#"{"key": "value"}"#))
.unwrap();
5. Client::new
Что делает: Создаёт новый HTTP-клиент для отправки запросов. Клиент использует пул соединений для повышения производительности.
Параметры: Не принимает параметров (есть перегруженная версия с конфигурацией).
Пример:
use hyper::Client;
let client = Client::new();
6. Client::request
Что делает: Отправляет HTTP-запрос и возвращает ответ. Это основной метод для выполнения запросов через клиент.
Параметры:
req: Request<Body>— сконструированный запрос.
Пример:
use hyper::{Body, Client, Request};
let client = Client::new();
let req = Request::builder()
.uri("http://httpbin.org/get")
.body(Body::empty())
.unwrap();
let resp = client.request(req).await.unwrap();
7. Body::from
Что делает: Создаёт тело HTTP-сообщения из различных источников: строки, вектора байт, файла или потока.
Параметры:
value: impl Into<Body>— данные для тела сообщения.
Пример:
use hyper::Body;
let body_from_string = Body::from("Hello");
let body_from_bytes = Body::from(vec![104, 101, 108, 108, 111]); // "hello" в байтах
8. Body::empty
Что делает: Создаёт пустое тело сообщения. Полезно для GET-запросов или ответов без содержимого.
Параметры: Не принимает параметров.
Пример:
use hyper::Body;
let empty_body = Body::empty();
9. StatusCode::from_u16
Что делает: Создаёт статус-код из числа. Позволяет использовать нестандартные или редко используемые коды.
Параметры:
code: u16— числовое значение статус-кода.
Пример:
use hyper::StatusCode;
let status = StatusCode::from_u16(418).unwrap(); // 418 I'm a teapot
println!("Статус: {}", status);
10. Uri::from_str
Что делает: Парсит строку в URI. Используется для создания корректных URI из строковых литералов.
Параметры:
s: &str— строка, представляющая URI.
Пример:
use hyper::Uri;
use std::str::FromStr;
let uri = Uri::from_str("https://api.example.com/v1/users").unwrap();
println!("Схема: {:?}", uri.scheme());
println!("Хост: {:?}", uri.host());
11. service_fn
Что делает: Создаёт сервис из асинхронной функции. Упрощает создание обработчиков запросов без реализации трейта Service вручную.
Параметры:
f: impl Fn(Request<Body>) -> Future— асинхронная функция-обработчик.
Пример:
use hyper::service::service_fn;
use hyper::{Body, Request, Response};
let handler = service_fn(|req: Request<Body>| async move {
let response = Response::new(Body::from("Hello from service_fn!"));
Ok::<_, Infallible>(response)
});
12. make_service_fn
Что делает: Создаёт фабрику сервисов, которая вызывается для каждого нового соединения. Позволяет создавать изолированные сервисы для каждого подключения.
Параметры:
f: impl Fn(&AddrStream) -> Future— функция, принимающая информацию о соединении и возвращающая сервис.
Пример:
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Response, Server};
let make_svc = make_service_fn(|socket