LibCpr: Windows环境下实现一个C++版本的Http客户端
近日,出于工作需要,需要实现一个C++版本的Http客户端。对比后,发现调用LibCpr库接口比较简洁、好用,以下是Windows环境下实现一个C++版本的Http客户端程序,已在本机验证可用。
C++代码:
#include <iostream>
#include <string>
#include <cpr/cpr.h>
#include <stdexcept>
#include <string_view>
#include <sstream>
#include <ctime>
#include <vector>
#include <optional>
#include <iomanip>using namespace std;// HTTP服务连接器类 (使用cpr::Session优化连接)
class HttpServiceConnector
{
public:explicit HttpServiceConnector(string_view baseUrl): base_url_(baseUrl){// 初始化会话session_.SetHeader(cpr::Header{ {"User-Agent", "C++ HTTP Client"} });session_.SetTimeout(cpr::Timeout{ 10000 });}// 向服务写入数据bool WriteData(string_view endpoint, string_view data){try{session_.SetUrl(cpr::Url{ BuildUrl(endpoint) });session_.SetHeader(cpr::Header{ {"Content-Type", "text/plain"} });session_.SetBody(cpr::Body{ data.data() });cpr::Response response = session_.Post();return HandleResponse(response, "写入");}catch (const exception& e){cerr << "写入异常: " << e.what() << "\n";return false;}}// 从服务查询数据optional<string> QueryData(string_view endpoint, const vector<pair<string, string>>& params = {}){try{// 构建查询参数cpr::Parameters cpr_params;for (const auto& [key, value] : params){cpr_params.Add({ key, value });}session_.SetUrl(cpr::Url{ BuildUrl(endpoint) });session_.SetParameters(cpr_params);cpr::Response response = session_.Get();if (HandleResponse(response, "查询")){return response.text;}return nullopt;}catch (const exception& e){cerr << "查询异常: " << e.what() << "\n";return nullopt;}}private:string base_url_; // 服务基础URLcpr::Session session_; // 复用HTTP会话// 构建完整URL (更健壮的实现)string BuildUrl(string_view endpoint) const{string url = base_url_;// 移除base_url末尾的斜杠if (!url.empty() && url.back() == '/') {url.pop_back();}// 添加endpoint前的斜杠if (!endpoint.empty()) {if (endpoint.front() != '/') {url += '/';}url += endpoint;}return url;}// 处理HTTP响应bool HandleResponse(const cpr::Response& response, string_view operation){if (response.error){cerr << operation << "错误: " << response.error.message << "\n";return false;}if (response.status_code >= 200 && response.status_code < 300){cout << operation << "成功! 状态码: " << response.status_code << "\n";return true;}cerr << operation << "失败! 状态码: " << response.status_code<< "\n错误信息: " << response.text << "\n";return false;}
};// 获取当前时间的 ISO 8601 格式字符串 (跨平台实现)
string GetCurrentTimestamp()
{time_t now = time(nullptr);tm timeInfo;// 跨平台UTC时间处理
#if defined(_WIN32)gmtime_s(&timeInfo, &now);
#elsegmtime_r(&now, &timeInfo);
#endifostringstream oss;oss << put_time(&timeInfo, "%Y-%m-%dT%H:%M:%SZ");return oss.str();
}// 传感器数据结构
struct SensorData
{string device_id = "sensor-001";string timestamp = GetCurrentTimestamp();vector<tuple<string, double, string>> readings = {{"temperature", 23.5, "°C"},{"humidity", 45.2, "%"},{"pressure", 1013.25, "hPa"}};pair<double, double> location = { 34.0522, -118.2437 };// 转换为字符串表示string ToString() const{ostringstream data;data << "Device: " << device_id << "\n"<< "Timestamp: " << timestamp << "\n";for (const auto& [name, value, unit] : readings) {data << name << ": " << value << unit << "\n";}data << "Location: " << location.first << ", " << location.second;return data.str();}
};int main() {// 配置服务端地址constexpr string_view base_url = "http://172.35.120.208:9521/HttpServerService";HttpServiceConnector httpClient(base_url);// 创建传感器数据SensorData sensor;const string sensorData = sensor.ToString();cout << "准备发送的数据:\n" << sensorData << "\n\n";// 写入数据bool writeSuccess = true;/* writeSuccess = httpClient.WriteData("post", sensorData);cout << "\n写入结果: " << (writeSuccess ? "成功" : "失败") << endl;*/// 查询数据cout << "\n查询最新数据...\n";vector<pair<string, string>> queryParams = {{"deviceId", sensor.device_id},{"type", "all"}};if (auto result = httpClient.QueryData("Query", queryParams)){cout << "\n查询结果:\n" << *result << "\n";}else{cout << "查询失败\n";}return writeSuccess ? EXIT_SUCCESS : EXIT_FAILURE;
}