You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

命令行cURL请求成功,但PHP curl_exec返回504网关超时的问题排查

PHP CURL请求返回504超时但命令行CURL正常的排查原因

问题场景

我尝试用PHP的curl_setopt发送请求获取数据,但请求加载2分钟后返回504 Gateway Timeout错误,PHP代码如下:

function sendRequest($url, $data, $token = '') {
    $header[] = "Connection: keep-alive";

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_HTTP_VERSION, 'CURL_HTTP_VERSION_1_1');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_VERBOSE, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36");

    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

奇怪的是,使用命令行CURL设置相同参数时,能立即成功获取数据:

curl --url "http://x.x.x.x" --header "Connection: keep-alive" --http1.1 --verbose --request "POST" -d "data1=value1" -d "data2=value2" --user-agent "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36"

部署代码的服务器与目标服务器处于同一网络,且两者均未启用防火墙,请问该故障的原因可能是什么?

可能的故障原因

  • POST数据格式不匹配:命令行用-d传递的是application/x-www-form-urlencoded格式的键值对,而PHP中如果$data是数组,curl会自动将请求编码为multipart/form-data,目标服务器可能无法解析这种格式,导致请求挂起超时。解决办法是用http_build_query($data)把数组转成表单编码字符串后再传入CURLOPT_POSTFIELDS。

  • CURLOPT_CUSTOMREQUEST的冗余设置冲突:当设置CURLOPT_POSTFIELDS时,curl会自动把请求方法设为POST,并添加对应Content-Type头部。手动设置CURLOPT_CUSTOMREQUEST = 'POST'会干扰curl的自动处理逻辑,可能导致请求头部不完整,目标服务器无法正确响应。解决办法是删除这一行代码。

  • IPv6解析导致的延迟:PHP curl默认可能优先尝试IPv6连接,若目标服务器没有配置IPv6地址,会等待IPv6连接超时后再 fallback 到IPv4,这会消耗大量时间。而命令行curl可能默认禁用IPv6或快速切换。解决办法是添加curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);强制使用IPv4解析。

  • Expect头部的延迟问题:PHP curl会自动添加Expect: 100-continue头部,部分服务器对这个头部的处理会导致请求延迟甚至超时,而命令行curl默认不会发送这个头部。解决办法是在自定义头部中添加$header[] = "Expect: ";来禁用该头部。

  • 未查看CURL详细日志:虽然开启了CURLOPT_VERBOSE,但PHP不会直接输出日志内容,无法定位请求过程中具体卡住的环节。可以添加日志输出代码,查看连接、发送、接收的详细过程:

$verboseLog = fopen('php://temp', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $verboseLog);
// 执行请求后读取日志
rewind($verboseLog);
$verboseOutput = stream_get_contents($verboseLog);
fclose($verboseLog);
var_dump($verboseOutput);

内容的提问来源于stack exchange,提问作者kneejar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 22:18:10