用libcurl实现http请求最稳,因其自动处理重定向、chunked编码、tls握手等复杂细节;手写socket易遇curle_recv_error或响应截断;需正确初始化、设url协议前缀、启用跳转、用writefunction攒整块响应体、post时先设postfields再设json头、windows下须指定ca证书路径。

用 libcurl 实现 GET 请求最稳,别手写 socket
直接上 libcurl,不是因为它“高级”,而是因为 HTTP 协议细节太多:重定向、chunked 编码、TLS 握手、header 大小限制、连接复用……手写 socket 容易在 CURLcode 返回 CURLE_RECV_ERROR 或静默截断响应时卡住半天。生产环境或快速验证,libcurl 是事实标准。
实操建议:
- 链接时加
-lcurl,头文件只用#include <curl></curl> - 必须调用
curl_global_init(CURL_GLOBAL_DEFAULT)一次(通常在 main 开头) -
curl_easy_setopt(handle, CURLOPT_URL, "https://httpbin.org/get")的 URL 必须带协议前缀,否则默认走 ftp - 设
CURLOPT_FOLLOWLOCATION为 1L 才能自动跳转,否则 302 响应体就是空的 - 用
CURLOPT_WRITEFUNCTION+CURLOPT_WRITEDATA捕获响应体,别依赖CURLOPT_HEADER——它只控制是否打印到 stdout,不存进你的 buffer
callback 函数里别直接 push_back 到 vector
常见错误是写一个 std::vector<:string> response_lines</:string>,然后在 write_callback 里做 response_lines.push_back(std::string(ptr, size))。问题在于:HTTP 响应体不按行分割,ptr 指向的是原始字节流,可能中途断在 UTF-8 多字节字符中间,也可能把一个 JSON 对象切成两段传进来。
正确做法是攒整块数据:
立即学习“C++免费学习笔记(深入)”;
- 声明
std::string response_body作为CURLOPT_WRITEDATA的目标 - callback 写成:
size_t write_callback(void* ptr, size_t size, size_t nmemb, void* userdata) { std::string* buf = static_cast<std::string*>(userdata); buf->append(static_cast<char*>(ptr), size * nmemb); return size * nmemb; } - 不要在 callback 里做解析、日志、网络调用——它可能被调用十几次,且不在主线程上下文(多线程模式下)
POST JSON 时 Content-Type 和 CURLOPT_POSTFIELDS 的顺序不能错
发 JSON 最容易 400 错误,根本原因不是 payload 写错了,而是 header 设置时机不对。libcurl 默认对 CURLOPT_POSTFIELDS 自动加 Content-Type: application/x-www-form-urlencoded,覆盖你手动设的 JSON 类型。
必须按这个顺序写:
- 先设
CURLOPT_POSTFIELDS(或CURLOPT_COPYPOSTFIELDS) - 再设
CURLOPT_HTTPHEADER,传入struct curl_slist*,例如:struct curl_slist* headers = nullptr; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
- 如果用
CURLOPT_POSTFIELDS,记得 payload 必须是 const char* 且生命周期覆盖整个请求;更安全用CURLOPT_COPYPOSTFIELDS,它会内部拷贝 - 别漏掉
CURLOPT_POST设为 1L,否则即使有 post fields 也发成 GET
Windows 下 curl_easy_perform 返回 CURLE_SSL_CACERT 要手动指定 CA
Linux/macOS 通常自带系统 CA bundle,Windows 的 libcurl 静态链接版默认找不到证书路径,curl_easy_perform 直接返回 CURLE_SSL_CACERT,连 DNS 都没开始查。
解决方法只有两个有效:
- 下载
curl-ca-bundle.crt(官方提供),然后:curl_easy_setopt(curl, CURLOPT_CAINFO, "path/to/curl-ca-bundle.crt");
- 或者关校验(仅测试用):
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
- 注意
CURLOPT_SSL_VERIFYHOST设为 0L 不等于 2L(旧版默认值),设成 2L 仍会校验域名,设成 0L 才彻底跳过
跨平台项目里,CA 路径最好通过配置或环境变量传入,硬编码路径在用户机器上大概率失效。










