Как создать простой HTTP-сервер на Rust с hyper или axum

7 минут чтения
Средний рейтинг статьи — 4.7

Создание собственного HTTP-сервера — это отличный способ познакомиться с экосистемой Rust и современными асинхронными возможностями языка. В этой статье мы рассмотрим два популярных подхода: с использованием hyper (низкоуровневой библиотеки для HTTP) и axum (высокоуровневого фреймворка, построенного на hyper и tower).

Hyper vs Axum: что выбрать для HTTP-сервера на Rust

Hyper — низкоуровневый HTTP toolkit

Преимущества:

  • Максимальная гибкость. Вы контролируете весь процесс обработки HTTP-запросов и ответов.
  • Быстродействие. Отсутствие дополнительной абстракции делает hyper очень лёгким и быстрым.
  • Минимум зависимостей. Подходит, если хотите минимальный бинарник или делаете что-то embedded.
  • Идеален для кастомных решений — например, если вам нужен нестандартный HTTP-сервер или прокси.

Недостатки:

  • Много кода. Простые вещи требуют много ручной работы (маршрутизация, обработка ошибок и пр.).
  • Крутая кривая обучения. Нужно хорошо понимать как работает async/await, lifetimes и hyper-сервисы.
  • Меньше готовых решений. Всё пишется вручную или с подключением сторонних компонентов.

Axum — высокоуровневый веб-фреймворк

Преимущества:

  • Быстрый старт. Почти как Express.js, только типизированный и на Rust.
  • Из коробки есть маршрутизация, middleware, работа с запросами и ответами, валидация, extractors.
  • Нативная интеграция с tower. Можно использовать middlewares, timeouts, логгеры и т.д.
  • Приятный DX (Developer Experience) — особенно если работали с web-фреймворками ранее.
  • Идеально для REST API и классических серверов.

Недостатки:

  • Меньше гибкости, чем у hyper. Некоторые сложные случаи могут быть нетривиальны.
  • Размер зависимостей больше — из-за tower, http-body и других фреймворков.
  • Нужно понимать, что происходит под капотом — axum делает многое «магически», что не всегда удобно при отладке.
Если вы хотите...Выбор
Минимальный сервер, встроенный в системуhyper
Учиться глубоко понимать HTTP + async Rusthyper
Быстрое создание API, удобную маршрутизациюaxum
REST-приложение или прототипaxum
Расширяемость и готовые middlewareaxum

Выбор между hyper и axum зависит от ваших целей. Если нужен полный контроль — берите hyper. Если хотите быстро и удобно запустить API — axum подойдёт лучше всего.

Подготовка окружения

Для начала убедитесь, что у вас установлен Rust. Если нет — установите его с помощью rustup:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Создадим новый проект:

cargo new rust-http-server
cd rust-http-server

Вариант 1: HTTP-сервер на hyper

Установка зависимостей

Добавьте в Cargo.toml:

[dependencies]
hyper = { version = "1", features = ["full"] }
tokio = { version = "1", features = ["full"] }

Простой сервер

Создайте src/main.rs:

use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};
use std::convert::Infallible;
 
async fn handle(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
    Ok(Response::new(Body::from("Привет от hyper!")))
}
 
#[tokio::main]
async fn main() {
    let addr = ([127, 0, 0, 1], 3000).into();
 
    let make_svc = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(handle))
    });
 
    let server = Server::bind(&addr).serve(make_svc);
 
    println!("Сервер запущен на http://{addr}");
 
    if let Err(e) = server.await {
        eprintln!("Ошибка сервера: {e}");
    }
}

Как запустить

cargo run

Откройте в браузере http://localhost:3000 — вы увидите Привет от hyper!

Вариант 2: HTTP-сервер на axum

Если вам нужен более удобный способ маршрутизации и работы с параметрами запроса, лучше использовать axum.

Установка зависимостей

[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }

Пример с маршрутизацией и параметрами

use axum::{Router, routing::get, http::StatusCode, response::IntoResponse, extract::Query};
use std::net::SocketAddr;
use std::collections::HashMap;
 
async fn root() -> &'static str {
    "Привет от axum!"
}
 
async fn echo(Query(params): Query<HashMap<String, String>>) -> impl IntoResponse {
    let response = format!("Получены параметры: {:?}", params);
    (StatusCode::OK, response)
}
 
#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(root))
        .route("/echo", get(echo));
 
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    println!("Сервер axum запущен на http://{addr}");
 
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

Примеры запросов

  • http://localhost:3000/ — просто возвращает строку.
  • http://localhost:3000/echo?name=Rust&lang=ru — выводит Получены параметры: {"name": "Rust", "lang": "ru"}

Заключение

Вы можете выбрать любой уровень абстракции, в зависимости от задач:

  • hyper — для полной гибкости и контроля.
  • axum — для быстрого и безопасного построения веб-приложений.

Обе библиотеки используют tokio и поддерживают современный асинхронный Rust. Следующий шаг — добавление middlewares, логирования, работы с базами данных и авторизации. Но всё начинается с простого запроса/ответа.

7 минут чтения
Средний рейтинг статьи — 4.7

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний