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

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

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

Начать курс

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

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