Introdução: por que escrever um cliente HTTP em C++?
No desenvolvimento moderno, a interação com servidores remotos é uma das tarefas principais. Seja obtendo dados de uma REST API, enviando um formulário para o servidor ou baixando um arquivo — o protocolo HTTP é usado em todos os lugares. Apesar de Python e JavaScript oferecerem soluções integradas simples, C++ continua sendo requisitado para escrever clientes HTTP de alto desempenho. Isso é necessário para sistemas embarcados, motores de jogos, backends de alta carga ou simplesmente para estudar os mecanismos de rede de baixo nível.
Neste artigo, vamos analisar duas abordagens populares para implementar um cliente HTTP em C++: o uso da biblioteca libcurl (cURL) e uma abordagem assíncrona mais moderna com Boost.Beast. Você aprenderá como formar corretamente requisições GET e POST, processar respostas e evitar erros típicos.
1. Abordagem clássica: cliente HTTP em C++ com libcurl
A biblioteca libcurl é uma ferramenta testada pelo tempo para transferência de dados através de vários protocolos. Ela suporta HTTP/1.1, HTTP/2, HTTPS, autenticação, cookies e muito mais. Para C++, existe um wrapper conveniente curl/curl.h que permite integrar facilmente o cURL no seu projeto.
Instalação do libcurl
Na maioria das distribuições Linux, o cURL já está instalado. Para desenvolvimento, você precisará do pacote de desenvolvimento:
sudo apt-get install libcurl4-openssl-dev # Ubuntu/Debianbrew install curl # macOSExemplo: requisição GET
Vamos escrever um cliente HTTP simples em C++ que obtém dados de uma API pública (por exemplo, JSONPlaceholder).
#include <iostream>#include <string>#include <curl/curl.h>
// Callback para escrever dados em std::stringstatic size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb;}
int main() { CURL *curl; CURLcode res; std::string readBuffer;
curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init();
if(curl) { 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, &readBuffer); // Executa a requisição res = curl_easy_perform(curl); if(res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { std::cout << "Resposta do servidor:" << readBuffer << std::endl; } curl_easy_cleanup(curl); } curl_global_cleanup(); return 0;}Exemplo: requisição POST com JSON
Agora vamos enviar dados para o servidor. Para isso, é necessário especificar o tipo de conteúdo e o corpo da requisição.
#include <iostream>#include <string>#include <curl/curl.h>
int main() { CURL *curl; CURLcode res; std::string response; // Dados JSON para enviar std::string jsonData = R"({"title": "foo", "body": "bar", "userId": 1})"; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://jsonplaceholder.typicode.com/posts"); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str()); // Define os cabeçalhos struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // Callback para escrever a resposta curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [](void *contents, size_t size, size_t nmemb, void *userp) -> siz