Как создать простой HTTP-сервер на Rust с hyper или axum
Создание собственного 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 Rust | hyper |
Быстрое создание API, удобную маршрутизацию | axum |
REST-приложение или прототип | axum |
Расширяемость и готовые middleware | axum |
Выбор между 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, логирования, работы с базами данных и авторизации. Но всё начинается с простого запроса/ответа.
Настроить мониторинг за 30 секунд
Надежные оповещения о даунтаймах. Без ложных срабатываний