libcurl 是 c++ 项目调用 elasticsearch rest api 最稳妥的选择,需禁用 ssl 证书校验、手动设置 json 请求头、用 nlohmann/json 解析响应、复用连接并重试、显式设 content-length 避免 chunked 编码问题。

用 libcurl 发起 GET/POST 请求最直接
不用封装库也能调通,libcurl 是 C++ 项目里最稳妥的选择。它不依赖 Boost 或现代 C++20 特性,Windows/macOS/Linux 都能编译过,而且 Elasticsearch 的 REST API 就是纯 HTTP,没必要上重型客户端。
常见错误现象:CURLOPT_SSL_VERIFYPEER 默认开启,内网自签证书时直接报 Peer's Certificate issuer is not recognized;或者忘记设 CURLOPT_HTTPHEADER,ES 返回 406 Not Acceptable(缺 Accept: application/json)。
- 必须手动设置请求头:
Content-Type: application/json(写文档、删索引等 POST/PUT 操作),Accept: application/json(所有请求) - GET 查询建议用
CURLOPT_URL拼完整地址(如"http://localhost:9200/my-index/_search"),别手写 query string 后再塞进POSTFIELDS - POST body 用
json::serialize()(或std::string拼接)后传给CURLOPT_POSTFIELDS,别传std::string::c_str()而不设CURLOPT_POSTFIELDSIZE,否则中文或二进制内容会截断
JSON 解析别硬写,用 nlohmann/json 省掉类型转换坑
Elasticsearch 返回的 JSON 结构灵活:搜索结果在外层有 hits,聚合结果在 aggregations,错误响应又变成 error + status。自己用 std::string::find 扒字段,两周后准崩溃。
使用场景:解析 _search 响应里的 hits.hits 数组,或判断 response["error"] 是否存在来区分成功/失败。
立即学习“C++免费学习笔记(深入)”;
-
nlohmann/json支持直接用response["hits"]["total"]["value"].get<int>()</int>,比at()安全,访问不存在 key 会抛json::out_of_range异常,而不是静默返回 null - 注意 ES 7+ 的
hits.total从数字变成对象({"value": 123, "relation": "eq"}),别还按老方式读response["hits"]["total"].get<int>()</int>,得先判类型:response["hits"]["total"].is_number_integer() - 如果用 C++17,推荐开
-DJSON_USE_IMPLICIT_CONVERSIONS=OFF编译选项,避免int被悄悄转成double导致精度丢失
连接池和重试不是可选项,是 libcurl 必须补的课
单次 curl_easy_init() + curl_easy_perform() 看似简单,但每请求都重建 TCP 连接,QPS 上不去;遇到 ES 临时抖动(比如分片恢复中),503 Service Unavailable 直接让业务报错,而不是等几秒重试。
性能影响:没复用连接时,100 QPS 可能触发几百个 TIME_WAIT;开了 CURLOPT_TCP_KEEPALIVE 和 CURLOPT_FORBID_REUSE(设为 0)后,连接复用率能到 80%+。
- 用
curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 20L)控制空闲连接上限,防 fd 耗尽 - 对
503、429、连接超时(CURLE_OPERATION_TIMEDOUT)做指数退避重试,最多 3 次,每次间隔100ms * 2^i - 别在重试逻辑里重复调
curl_easy_init()—— 复用同一个CURL*句柄,只重设CURLOPT_URL和CURLOPT_POSTFIELDS
别忽略 Content-Length 和 chunked encoding 的隐式切换
当 POST body 是动态生成(比如拼接了用户输入的查询条件),且没显式设 Content-Length,libcurl 会自动切到 Transfer-Encoding: chunked。而某些老旧 ES 代理(比如 Nginx 未配 chunked_transfer_encoding on)会直接拒收,返回空响应或 400 Bad Request。
兼容性影响:ES 本身支持 chunked,但中间件不一定。Kubernetes Ingress、AWS ALB 默认禁用 chunked,容易卡在这里。
- 显式计算 body 长度,用
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length()),这样libcurl就发Content-Length而非 chunked - 如果 body 来自流式生成(比如大 bulk 导入),必须确保反向代理支持 chunked,Nginx 要加
chunked_transfer_encoding on;,ALB 要开enable_http2(HTTP/2 自带 frame 分块) - 调试时用
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L)看真实发出的请求头,确认有没有Transfer-Encoding: chunked
ES 的 HTTP 接口看着简单,但连通性、JSON 结构漂移、中间件兼容这三块最容易漏测。尤其上线前得用真实集群跑一遍带中文、特殊字符、嵌套聚合的请求,光本地 mock 不顶事。










