Introduction : pourquoi écrire un client HTTP en C++ ?
Dans le développement moderne, l'interaction avec des serveurs distants est l'une des tâches clés. Qu'il s'agisse de récupérer des données d'une API REST, d'envoyer un formulaire à un serveur ou de télécharger un fichier, le protocole HTTP est utilisé partout. Bien que Python et JavaScript offrent des solutions intégrées simples, le C++ reste très demandé pour écrire des clients HTTP hautes performances. Cela est nécessaire pour les systèmes embarqués, les moteurs de jeux, les backends à forte charge ou simplement pour étudier les mécanismes réseau de bas niveau.
Dans cet article, nous allons examiner deux approches populaires pour implémenter un client HTTP en C++ : l'utilisation de la bibliothèque libcurl (cURL) et une approche asynchrone plus moderne avec Boost.Beast. Vous apprendrez à formater correctement les requêtes GET et POST, à traiter les réponses et à éviter les erreurs typiques.
1. Approche classique : client HTTP en C++ avec libcurl
La bibliothèque libcurl est un outil éprouvé pour le transfert de données sur divers protocoles. Elle prend en charge HTTP/1.1, HTTP/2, HTTPS, l'authentification, les cookies et bien plus encore. Pour C++, il existe un wrapper pratique curl/curl.h qui permet d'intégrer facilement cURL dans votre projet.
Installation de libcurl
Dans la plupart des distributions Linux, cURL est déjà installé. Pour le développement, vous aurez besoin du paquet de développement :
sudo apt-get install libcurl4-openssl-dev # Ubuntu/Debianbrew install curl # macOSExemple : requête GET
Écrivons un client HTTP simple en C++ qui récupère des données d'une API publique (par exemple, JSONPlaceholder).
#include <iostream>#include <string>#include <curl/curl.h>
// Callback pour écrire les données dans 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); // Exécuter la requête res = curl_easy_perform(curl); if(res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { std::cout << "Réponse du serveur :" << readBuffer << std::endl; } curl_easy_cleanup(curl); } curl_global_cleanup(); return 0;}Exemple : requête POST avec JSON
Maintenant, envoyons des données au serveur. Pour cela, il faut spécifier le type de contenu et le corps de la requête.
#include <iostream>#include <string>#include <curl/curl.h>
int main() { CURL *curl; CURLcode res; std::string response; // Données JSON à envoyer 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()); // Définir les en-têtes struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // Callback pour écrire la réponse curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [](void *contents, size_t size, size_t nmemb, void *userp) -> siz