curl_errno非零时需立即用curl_error和curl_getinfo定位:http_code为0说明dns或tcp层失败,否则查ssl、超时等具体环节;须设connecttimeout和timeout_ms防卡顿;ssl错误需配cainfo并指定tls版本。

curl_errno 返回非零值时,怎么定位具体失败环节
直接看 curl_errno 的返回数字没用,必须配合 curl_error 和 curl_getinfo 才能判断是 DNS 解析失败、连接超时、SSL 验证失败,还是远端返回了 4xx/5xx。常见错误码如 CURLE_COULDNT_RESOLVE_HOST(6)、CURLE_OPERATION_TIMEDOUT(28)、CURLE_SSL_CONNECT_ERROR(35)——但这些常量在低版本 PHP 中可能未定义,所以优先用 curl_error($ch) 看原始提示。
- 调用
curl_exec后立即检查:if (curl_errno($ch)) { echo curl_error($ch); } - 再查协议层信息:
print_r(curl_getinfo($ch));关注http_code、connect_time、pretransfer_time、ssl_verify_result - 若
http_code是 0,基本说明请求根本没发出去(DNS 或 TCP 层就卡住了);若大于 0 但非 200,说明服务端有响应,问题在业务逻辑或权限控制
为什么设置了 CURLOPT_TIMEOUT 却还是卡住十几秒才报错
因为 CURLOPT_TIMEOUT 控制的是整个请求生命周期(DNS + 连接 + 传输),而 CURLOPT_CONNECTTIMEOUT 才管“连上服务器前”的等待时间。如果 DNS 解析慢或目标 IP 不可达,只设 TIMOUT 没用,必须显式设 CONNECTTIMEOUT(建议 ≤ 5)和 TIMEOUT_MS(毫秒级更准,需 libcurl ≥ 7.16.2)。
-
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);—— 连接建立超时 -
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 8000);—— 总耗时上限(毫秒),比TIMEOUT更精确 - 避免只设
TIMEOUT,否则 DNS 卡住时会等满整秒才触发,实际耗时不可控
SSL 报错 CURLE_SSL_CONNECT_ERROR(35)的常见诱因和验证方式
这个错误不等于证书过期,更可能是本地 CA 证书路径不对、服务端用了不兼容的 TLS 版本、或 OpenSSL 库太老。PHP 默认不校验证书(CURLOPT_SSL_VERIFYPEER 默认为 true,但若没配 CURLOPT_CAINFO 就会失败),所以不能简单关掉验证来“修复”。
- 先确认是否启用了验证:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);,然后必须配CURLOPT_CAINFO指向有效的 PEM 文件(如/etc/ssl/certs/ca-certificates.crt) - 强制指定 TLS 版本:
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);(避免协商到 TLS 1.0) - 临时调试可加
curl_setopt($ch, CURLOPT_VERBOSE, true);查看握手过程中的具体失败点(输出到 stdout,注意别在生产环境开)
curl_getinfo($ch) 的关键字段怎么看才不误导
curl_getinfo 返回数组里有些字段容易误读:比如 http_code 是响应状态码,但若请求根本没发出去,它就是 0;size_upload 和 size_download 是字节数,不是布尔值;redirect_count 为 0 不代表没跳转,可能 follow_location 没开。
立即学习“PHP免费学习笔记(深入)”;
- 判断是否真正发出请求:看
http_code !== 0且connect_time > 0 - 上传失败?查
size_upload === 0且upload_content_length > 0 - 重定向被拦截?确认是否设置了
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);,否则redirect_count永远是 0 - 不要只盯着
http_code,它只是 HTTP 层结果,底层失败时它毫无意义
curl_exec 后立刻捕获 curl_errno 和 curl_error,而是先做其他逻辑,导致错误上下文丢失;还有就是把 http_code === 0 当成“网络不通”,其实也可能是 curl_close 被提前调用了。











