curl_exec() 返回 false 的常见原因有三:一是 CURLOPT_NOBODY 与 CURLOPT_RETURNTRANSFER 冲突导致无响应体或输出到屏幕;二是未设超时致卡死,需显式配置 CURLOPT_CONNECTTIMEOUT 和 CURLOPT_TIMEOUT;三是 POST 数据类型或编码不匹配目标接口要求。

curl_exec() 返回 false 但没报错?先检查 CURLOPT_RETURNTRANSFER 和 CURLOPT_NOBODY
这是最常被忽略的配置冲突:如果误设了 CURLOPT_NOBODY => true,cURL 会只发请求头、不收响应体,curl_exec() 看似“无响应”,其实它根本没去读 body。同时,CURLOPT_RETURNTRANSFER 必须设为 true,否则 curl_exec() 默认直接输出到 stdout(你可能根本没看到),而不是返回字符串。
实操建议:
- 始终显式设置
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true) - 确认没意外开启
CURLOPT_NOBODY或CURLOPT_HEADER(除非你真只要头) - 加一句
var_dump(curl_error($ch));在curl_exec()后,别只看返回值是否为 false
超时卡死几十秒?重点盯 CURLOPT_TIMEOUT 和 CURLOPT_CONNECTTIMEOUT
默认超时是无限的,一旦目标服务器 hang 住或 DNS 解析失败,PHP 进程就卡在那里,Web 请求直接 504,CLI 下等得怀疑人生。必须手动设两个超时:
-
CURLOPT_CONNECTTIMEOUT:仅控制 TCP 连接建立阶段(含 DNS 查询),建议设 5~10 秒 -
CURLOPT_TIMEOUT:控制整个请求生命周期(连接 + 发送 + 接收),建议设 15~30 秒,且必须 >CONNECTTIMEOUT - 别用
CURLOPT_TIMEOUT_MS除非你确定对方支持毫秒级精度(某些旧版 cURL 不兼容)
示例关键行:curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8); curl_setopt($ch, CURLOPT_TIMEOUT, 25);
立即学习“PHP免费学习笔记(深入)”;
对方服务器收不到 POST 数据?检查 CURLOPT_POSTFIELDS 类型和编码
传数组 vs 传字符串行为完全不同:curl_setopt($ch, CURLOPT_POSTFIELDS, ['key'=>'val']) 会自动设 Content-Type: multipart/form-data;而传 URL 编码字符串(如 'key=val&foo=bar')才对应 application/x-www-form-urlencoded。很多接口只认后者。
- 若需
application/json,必须手动设 header:curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']),且CURLOPT_POSTFIELDS传json_encode($data) - 中文或特殊字符务必确保源数据是 UTF-8,否则
json_encode()可能返回 null - 用
curl_getinfo($ch, CURLINFO_REQUEST_HEADER)打印实际发出的请求头,比猜靠谱得多
本地能通、线上 502/504?查服务器 outbound 网络策略和 DNS
PHP 脚本在 CLI 下跑通,不代表 Web 服务器(如 Nginx+PHP-FPM)环境也通——常见于容器或云主机:
- 检查 PHP 进程运行用户是否被防火墙限制 outbound(尤其阿里云安全组、腾讯云网络 ACL)
- Web 服务器可能用了自定义 DNS(如
/etc/resolv.conf里是内网 DNS),导致无法解析目标域名 - 用
curl -v http://example.com在 PHP-FPM 所在机器上手动测试,复现真实环境 - 临时加
curl_setopt($ch, CURLOPT_VERBOSE, true)并捕获 stderr,能看到 DNS 查询、TCP 握手是否卡在某步
超时问题真正的难点从来不在代码写法,而在你没法一眼看出是卡在 DNS、SYN、SSL 握手,还是对方应用层压根没启动。把 CURLOPT_VERBOSE 和系统级 tcpdump 配合着看,比反复改 PHP 更快定位。











