用 libcurl 发 get 请求最稳,因其自动处理重定向、gzip、ssl、连接复用和超时;需正确调用 curl_global_init/cleanup,设置 url、超时及 writefunction 捕获响应。

用 libcurl 发 GET 请求最稳,别碰裸 socket
直接写 socket 拼 HTTP 报文看似可控,实际要手动处理重定向、gzip 解压、SSL 验证、连接复用、超时逻辑——99% 的项目不值得为这点“控制感”付出维护成本。libcurl 是 C++ 做 HTTP 最现实的选择,C API 但 C++ 调用完全没问题。
常见错误:漏掉 curl_global_init(CURL_GLOBAL_DEFAULT),导致首次调用 curl_easy_init() 返回 nullptr;或者没设 CURLOPT_FOLLOWLOCATION,302 重定向就卡住。
- 必须在程序启动时调一次
curl_global_init(CURL_GLOBAL_DEFAULT),退出前调curl_global_cleanup() - GET 请求只需设
CURLOPT_URL和CURLOPT_HTTPGET(或留空,GET 是默认方法) - 加
CURLOPT_TIMEOUT和CURLOPT_CONNECTTIMEOUT,否则 DNS 卡住会挂死几十秒 - 响应体默认输出到 stdout,务必用
CURLOPT_WRITEFUNCTION+CURLOPT_WRITEDATA捕获到std::string或std::vector<char></char>
POST 提交 JSON 时 Content-Type 和数据格式不能错
发 JSON 不是把字符串塞进 CURLOPT_POSTFIELDS 就完事。Content-Type 缺失或写成 application/x-www-form-urlencoded,后端很可能收不到 body 或解析失败。
典型现象:后端日志显示收到空 body,或报 “invalid JSON”,但用 curl 命令行能通——大概率是 C++ 代码里没设 header 或数据指针生命周期出问题。
- 必须显式设置 header:
struct curl_slist* headers = nullptr; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); -
CURLOPT_POSTFIELDS接的是const char*,确保传入的 JSON 字符串内存有效(别传局部std::string::c_str()后立刻析构) - 如果用
std::string json_str = R"({"key":"val"})";,传json_str.c_str()是安全的,但得保证json_str生命周期覆盖整个curl_easy_perform()调用 - 不要用
CURLOPT_POST+CURLOPT_POSTFIELDSIZE组合来发 JSON,容易因长度计算错误截断
Windows 下链接 libcurl 容易缺 -lcurl 或 SSL 库
Linux/macOS 用 pkg-config --libs libcurl 一般能拉全依赖;Windows 上 MinGW 或 MSVC 手动链接时,漏库就直接报 undefined reference to 'curl_easy_init' 或更诡异的 SSL 相关符号找不到。
常见错误:只加了 -lcurl,但没连 -lssl -lcrypto(OpenSSL 版本)或 -lws2_32 -lwldap32(Windows SChannel 版本);或者用了静态链接但没定义 CURL_STATICLIB 宏。
- MinGW:除了
-lcurl,至少补-lssl -lcrypto -lz -lnghttp2(按你编译 libcurl 时启用的特性选) - MSVC:用预编译二进制时,确认下载的是带 OpenSSL 的版本(不是 WinSSL),并把
libcurl.lib、libeay32.lib、ssleay32.lib全加进 linker input - 用 CMake 时,优先走
find_package(CURL REQUIRED),比手写target_link_libraries少踩一半坑
异步请求?别自己撸线程池,先看 curl_multi
想并发发 10 个请求,第一反应是开 10 个线程各跑一个 curl_easy_perform()——这会吃光文件描述符、触发 TCP TIME_WAIT 爆满、还难统一管理超时和取消。
curl_multi 是 libcurl 内置的多路复用接口,基于 select/poll/epoll/kqueue,单线程就能高效并发。但它不是“开箱即用”,得自己轮询事件、处理完成回调。
- 初始化用
curl_multi_init(),每个请求仍需独立的CURL*句柄,再用curl_multi_add_handle()挂进去 - 主循环里调
curl_multi_perform()触发 I/O,再用curl_multi_info_read()检查哪些完成了 - 别在回调里做耗时操作(比如解析 JSON),只存结果、发信号,让主线程处理
- 如果已有 event loop(如 Qt 的
QEventLoop或 libuv),可用curl_multi_socket_action()接入,避免阻塞
真正麻烦的从来不是发请求本身,而是怎么让一堆请求不互相干扰、超时能及时回收、错误能准确定位到具体哪个 URL——这些细节藏在 curl_multi 的状态机和回调里,文档里不会明说,但绕不开。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











