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

PHP cURL请求大体积JSON数据超时问题求助

问题分析与解决方案

核心问题

Postman可在8分钟内获取包含5000+带变体产品的2MB JSON响应,但PHP cURL请求超时1小时后失败,Nginx日志报upstream timed out (110: Connection timed out) while reading response header from upstream,仅限制响应数据量时请求成功。

为什么Postman可行但PHP不行?

  1. 超时参数配置差异:Postman默认的连接/读取超时阈值远高于当前PHP cURL的设置,且对长连接的处理更宽松。
  2. 响应处理方式不同:Postman会流式处理分块响应,而当前PHP代码是一次性等待完整响应返回,若ERP接口采用分块传输,PHP可能因等待全部数据触发超时。
  3. 服务器端客户端识别策略:部分ERP接口会根据请求头(如User-Agent)调整超时策略,Postman的默认User-Agent可能被接口服务器允许更长的连接时间。

可能的原因

  • cURL超时参数不全:仅设置CURLOPT_TIMEOUT不够,缺少连接阶段的超时控制,或未启用更精确的毫秒级超时。
  • Nginx上游超时限制:服务器Nginx配置中proxy_read_timeout、proxy_connect_timeout等参数可能小于PHP的max_execution_time,导致Nginx提前终止连接。
  • 未启用分块读取:一次性获取大响应会占用更多资源,且容易触发服务器端的超时策略。

解决方案

1. 完善cURL参数配置

补充关键超时参数,调整HTTP版本,模拟Postman的请求头:

$curl = curl_init();
curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://api.anqodo.com:8088/anqDataSvc/api/TofererExternal/webshopproducts?ws_id=' . $webshop_id . '&date_from=' . $date_from,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => 'gzip, deflate', // 明确指定压缩方式,减少传输体积
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 3600, // 总超时时间
    CURLOPT_CONNECTTIMEOUT => 300, // 连接阶段超时(5分钟)
    CURLOPT_TIMEOUT_MS => 3600000, // 毫秒级总超时,避免整数溢出
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, // 固定HTTP版本,避免协议协商耗时
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => array(
        'RequestTimeClient: ' . date("Y-m-d\TH:i:s\Z"),
        'Content-Type: application/json',
        'Authorization: Bearer ' . $token,
        'User-Agent: PostmanRuntime/7.36.3' // 模拟Postman的User-Agent
    ),
    CURLOPT_FORBID_REUSE => false, // 允许复用连接
    CURLOPT_TCP_KEEPALIVE => true // 启用TCP保活,防止连接被中途断开
));

// 调试cURL错误
$response = curl_exec($curl);
if(curl_errno($curl)){
    error_log('cURL Error: ' . curl_error($curl));
}
$responseData = json_decode($response);
curl_close($curl);

return $responseData;

2. 启用流式读取响应

避免一次性加载全部响应到内存,用回调函数分块读取:

$responseBuffer = '';
$curl = curl_init();
curl_setopt_array($curl, array(
    // 其他参数同上
    CURLOPT_WRITEFUNCTION => function($ch, $data) use (&$responseBuffer) {
        $responseBuffer .= $data;
        return strlen($data);
    }
));

curl_exec($curl);
curl_close($curl);
$responseData = json_decode($responseBuffer);
return $responseData;

3. 调整Nginx配置

修改服务器的Nginx配置文件(如nginx.conf或站点配置),延长上游超时时间:

location ~ \.php$ {
    # 其他配置...
    proxy_read_timeout 3600s;
    proxy_connect_timeout 300s;
    proxy_send_timeout 3600s;
    fastcgi_read_timeout 3600s; # 若用fastcgi处理PHP
}

修改后重启Nginx:sudo systemctl restart nginx

4. 采用分页请求(最优方案)

如果ERP接口支持分页参数(如page、per_page),拆分请求为多个小批量请求,比如每次获取1000个产品:

$totalProducts = 5000;
$perPage = 1000;
$allProducts = [];

for($page = 1; $page <= ceil($totalProducts / $perPage); $page++){
    $curl = curl_init();
    $url = 'https://api.anqodo.com:8088/anqDataSvc/api/TofererExternal/webshopproducts?ws_id=' . $webshop_id . '&page=' . $page . '&per_page=' . $perPage;
    curl_setopt_array($curl, array(
        CURLOPT_URL => $url,
        // 其他cURL参数同上
    ));
    $response = curl_exec($curl);
    $pageProducts = json_decode($response);
    $allProducts = array_merge($allProducts, $pageProducts);
    curl_close($curl);
    // 可选:添加延迟,避免频繁请求触发接口限流
    sleep(2);
}

return $allProducts;

如果接口没有公开分页参数,联系ERP开发方添加该功能,这是最稳定的大数量数据同步方案。

5. 调试与排查

  • 用curl_error($curl)获取cURL的具体错误信息,定位是连接超时、读取超时还是其他问题。
  • 检查服务器的PHP错误日志,确认是否有内存溢出或其他PHP层面的错误。

内容的提问来源于stack exchange,提问作者DP-Timon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:30:34