HTTP клиент на C++: делаем запросы правильно от А до Я
В современном мире разработки программного обеспечения умение взаимодействовать с удаленными серверами через HTTP — это базовый навык. Будь то загрузка данных с API, отправка форм или работа с веб-сервисами, C++ предоставляет несколько мощных инструментов для создания HTTP-клиентов. В этой статье мы разберем, как правильно делать HTTP-запросы на C++, рассмотрим популярные библиотеки и напишем рабочие примеры кода.
Почему C++ для HTTP-запросов?
C++ не имеет встроенной поддержки HTTP в стандартной библиотеке, в отличие от Python или JavaScript. Однако это не проблема: существуют проверенные временем библиотеки, которые позволяют легко и эффективно отправлять запросы. Основные варианты:
- libcurl (cURL) — самая популярная кроссплатформенная библиотека.
- Boost.Beast — современная библиотека на основе Boost.Asio.
- WinHTTP — встроенное решение для Windows.
- Qt Network — для проектов на Qt.
В этой статье мы сосредоточимся на первых двух, так как они наиболее универсальны и подходят для большинства задач.
1. HTTP-клиент с использованием libcurl
libcurl — это проверенная годами библиотека, которая поддерживает HTTP, HTTPS, FTP и множество других протоколов. Она проста в использовании и отлично документирована.
Установка libcurl
Для Linux (Ubuntu/Debian):
sudo apt-get install libcurl4-openssl-dev
Для Windows можно скачать предварительно собранные бинарные файлы с официального сайта curl.se или использовать vcpkg:
vcpkg install curl
Простой GET-запрос
Напишем базовый пример получения данных с сервера:
#include <iostream>
#include <string>
#include <curl/curl.h>
// Функция обратного вызова для записи данных
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
size_t totalSize = size * nmemb;
output->append((char*)contents, totalSize);
return totalSize;
}
int main() {
CURL* curl = curl_easy_init();
if (!curl) {
std::cerr << "Ошибка инициализации CURL" << std::endl;
return 1;
}
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "https://jsonplaceholder.typicode.com/posts/1");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // Отключаем проверку SSL для теста
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::cerr << "Ошибка запроса: " << curl_easy_strerror(res) << std::endl;
} else {
std::cout << "Ответ сервера:\n" << response << std::endl;
}
curl_easy_cleanup(curl);
return 0;
}
Компилировать нужно с флагом -lcurl:
g++ -o http_client http_client.cpp -lcurl
POST-запрос с отправкой JSON
Теперь добавим отправку данных:
#include <iostream>
#include <string>
#include <curl/curl.h>
int main() {
CURL* curl = curl_easy_init();
if (!curl) return 1;
std::string response;
std::string jsonData = R"({"title": "foo", "body": "bar", "userId": 1})";
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL, "https://jsonplaceholder.typicode.com/posts");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK) {
std::cout << "POST ответ:\n" << response << std::endl;
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return 0;
}
2. HTTP-клиент с использованием Boost.Beast
Boost.Beast — это мощная библиотека для работы с HTTP и WebSocket на основе Boost.Asio. Она дает полный контроль над процессом и идеально подходит для асинхронных приложений.
Установка Boost
На Linux:
sudo apt-get install libboost-all-dev
На Windows через vcpkg:
vcpkg install boost-beast
Синхронный GET-запрос
#include <iostream>
#include <string>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = net::ip::tcp;
int main() {
try {
net::io_context ioc;
tcp::resolver resolver(ioc);
beast::tcp_stream stream(ioc);
// Разрешаем домен и устанавливаем соединение
auto const results = resolver.resolve("jsonplaceholder.typicode.com", "80");
stream.connect(results);
// Формируем GET-запрос
http::request<http::string_body> req{http::verb::get, "/posts/1", 11};
req.set(http::field::host, "jsonplaceholder.typicode.com");
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Отправляем запрос
http::write(stream, req);
// Получаем ответ
beast::flat_buffer buffer;
http::response<http::dynamic_body> res;
http::read(stream, buffer, res);
// Выводим результат
std::cout << "Статус: " << res.result_int() << std::endl