Введение
Когда нужно быстро поднять HTTP API внутри Qt-приложения — например, для локального управления десктопным приложением через браузер или для тестового стенда — необязательно подключать тяжёлые сторонние фреймворки. Начиная с Qt 6, в составе Qt HTTP Server есть класс QHttpServer, который позволяет описать маршруты в декларативном стиле, похожем на Express.js или Flask. В статье построим простой REST-сервер с несколькими эндпоинтами.
Концепция
QHttpServer регистрирует обработчики маршрутов через route(), указывая шаблон пути, HTTP-метод и лямбда-функцию, которая принимает параметры из пути и возвращает ответ. Сервер сам разбирает HTTP-запросы, работает поверх QTcpServer (или QSslServer для HTTPS) и поддерживает параметры пути, JSON-ответы через QHttpServerResponse и обработку ошибок 404 через setMissingHandler().
Это решение хорошо подходит для встроенных API средней нагрузки — не для высоконагруженных публичных сервисов, где более уместны специализированные C++ HTTP-фреймворки или обратные прокси.
Пример кода: QHttpServer
#include <QCoreApplication>
#include <QHttpServer>
#include <QJsonObject>
#include <QJsonArray>
#include <QTcpServer>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QHttpServer server;
server.route("/api/status", QHttpServerRequest::Method::Get, []() {
QJsonObject obj;
obj["status"] = "ok";
obj["version"] = "1.0.0";
return QHttpServerResponse(QJsonDocument(obj).toJson(),
"application/json");
});
server.route("/api/users/<arg>", QHttpServerRequest::Method::Get, [](int userId) {
QJsonObject obj;
obj["id"] = userId;
obj["name"] = QString("User #%1").arg(userId);
return QHttpServerResponse(QJsonDocument(obj).toJson(),
"application/json");
});
server.route("/api/echo", QHttpServerRequest::Method::Post,
[](const QHttpServerRequest &request) {
return QHttpServerResponse(request.body(), "application/json");
});
server.setMissingHandler(&server, [](const QHttpServerRequest &, QHttpServerResponder &&responder) {
responder.write(QByteArray("{\"error\":\"not found\"}"),
"application/json",
QHttpServerResponder::StatusCode::NotFound);
});
auto tcpServer = new QTcpServer(&server);
if (!tcpServer->listen(QHostAddress::Any, 8080) || !server.bind(tcpServer)) {
qWarning("Не удалось запустить сервер на порту 8080");
return 1;
}
qInfo("REST-сервер запущен: http://127.0.0.1:8080");
return app.exec();
}
Пояснения к коду
Каждый вызов route() связывает шаблон URL с обработчиком. Шаблон <arg> автоматически извлекает значение из пути и приводит его к типу параметра лямбды (в примере — int userId). Для POST-запроса /api/echo обработчик принимает QHttpServerRequest целиком и возвращает тело запроса обратно — простой способ показать работу с входящими данными.
setMissingHandler() определяет, что вернуть, если ни один маршрут не подошёл — это аналог обработчика 404 в других фреймворках. Сервер привязывается к явно созданному QTcpServer через bind(), что даёт контроль над адресом и портом прослушивания.
Подводные камни
QHttpServer— однопоточный по умолчанию. Долгие синхронные операции в обработчике маршрута блокируют обработку всех остальных запросов — для тяжёлых вычислений выносите работу вQtConcurrentили пул потоков, возвращая ответ asynchronно черезQHttpServerResponseс future.- Отсутствие встроенной авторизации/rate-limiting. В отличие от полнофункциональных веб-фреймворков,
QHttpServerне предоставляет готовых механизмов аутентификации — их нужно реализовывать вручную в каждом обработчике или через middleware-подобную обёртку. - Версионная нестабильность API.
QHttpServerпоявился относительно недавно и API менялся между минорными версиями Qt 6 — стоит сверяться с документацией конкретной версии при обновлении Qt. - Ограниченная поддержка статических файлов и стриминга. Для раздачи большого количества статики или потокового видео лучше использовать выделенный веб-сервер (nginx) перед Qt-приложением, а
QHttpServerоставить для API.