CURLE_COULDNT_RESOLVE_HOST 表示 DNS 解析失败,需检查 URL 完整性、系统 DNS 配置及是否误拼 host;响应体存入 std::string 需用 CURLOPT_WRITEFUNCTION 自定义回调;POST JSON 要正确设置 Content-Type 和 POSTFIELDS;复用 handle 前必须 curl_easy_reset 或手动重置关键选项。

curl_easy_perform 返回 CURLE_COULDNT_RESOLVE_HOST 怎么办
域名解析失败,不是网络不通,而是 DNS 查不到。常见于没设 CURLOPT_URL、URL 拼错(比如漏了 http://)、或系统 DNS 配置异常。
- 检查
curl_easy_setopt(handle, CURLOPT_URL, "https://api.example.com")是否传了完整 URL,协议头不能省 - 用
curl -v https://api.example.com在终端验证是否能通——如果命令行也失败,说明是环境问题,不是代码问题 - 在代码里加
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L),看日志里实际尝试解析的 host 是什么,常会暴露拼接错误(比如"https://api.example.com/" + "/v1/data"导致 URL 变成https://api.example.com//v1/data) - 某些嵌入式环境不支持 IPv6,可强制走 IPv4:
curl_easy_setopt(handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4)
怎么把响应体存进 std::string 而不是直接打印
libcurl 默认把响应写到 stdout,得自己接管写入逻辑,靠 CURLOPT_WRITEFUNCTION + CURLOPT_WRITEDATA 配合实现。
- 写一个 static 回调函数,签名必须是
size_t write_callback(void* ptr, size_t size, size_t nmemb, void* userp),返回实际处理的字节数 -
userp传入&std::string的地址,回调里用static_cast<:string>(userp)->append(...)</:string>追加数据 - 注意:
ptr不是以\0结尾的字符串,size * nmemb才是真实字节数,别直接当 C 字符串用 - 别在回调里做耗时操作(比如再发一次 curl 请求),否则阻塞整个传输
static size_t write_to_string(void* ptr, size_t size, size_t nmemb, void* userp) {
std::string& buf = *static_cast<std::string*>(userp);
buf.append(static_cast<char*>(ptr), size * nmemb);
return size * nmemb;
}
// 使用时:
std::string response;
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
POST JSON 数据时 Content-Type 和数据长度容易出错
服务器拒收、返回 400 或空响应,大概率是 Content-Type 没设对,或 body 没传进去。
- 必须显式设置
Content-Type: application/json,用curl_slist_append(headers, "Content-Type: application/json"),再curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers) - JSON 字符串要传给
CURLOPT_POSTFIELDS,不是CURLOPT_COPYPOSTFIELDS(后者会内部拷贝,但若传的是临时std::string.c_str(),可能悬垂) - 如果 JSON 内容含中文或特殊字符,确保字符串编码是 UTF-8,且没被
\0截断 - 调试时加
curl_easy_setopt(handle, CURLOPT_HEADER, 1L)看响应头,确认服务器是否返回了Content-Type: application/json,避免前端误判
libcurl 多次复用 handle 时忘记重置选项
第二次请求行为诡异(比如还带着上次的 POST body、header、超时时间),基本是没清状态。libcurl 的 handle 不是“无状态对象”,很多选项会持续生效。
立即学习“C++免费学习笔记(深入)”;
- 每次新请求前,调用
curl_easy_reset(handle)最省事——它会清掉所有curl_easy_setopt设置过的选项(除了CURLOPT_SHARE等少数几个) - 如果不重置,至少手动覆盖关键项:
CURLOPT_URL、CURLOPT_POSTFIELDS、CURLOPT_HTTPHEADER、CURLOPT_TIMEOUT,否则旧值还在 - 注意
curl_slist是独立分配的内存,curl_easy_reset不会自动释放它,得自己curl_slist_free_all(headers) - 多线程下别共用同一个 handle,哪怕加锁也不推荐;每个线程用独立 handle,或用
CURLMOPT_MAXCONNECTS控制连接池更稳妥
实际跑起来最常卡在 DNS 解析和 header 未清理这两步,尤其从示例代码抄过来时,容易只改 URL 忘了清 POST 数据或 headers。










