如何在循环中安全执行多个 HTTP POST 请求以避免超时

在共享主机环境下,php 脚本通过 curl 在循环中连续发起多个耗时请求时,总执行时间会累加并触发 `max_execution_time` 限制(如 120 秒),即使每次请求独立完成——根本原因在于 php 脚本的**整体生命周期未中断**,而非请求本身被“合并”。

你遇到的 Fatal error: Maximum execution time of 120 seconds exceeded 并非由 cURL 超时引起,而是 PHP 解释器自身执行时间超限。你的循环中两次请求分别耗时 32s 和 50s,已累计 82s;若后续还有其他逻辑或网络波动导致延迟,极易突破 120 秒硬性上限——而共享主机通常禁止修改 max_execution_time,因此必须从控制脚本节奏优化请求模式入手。

✅ 正确做法:主动引入间隔与容错机制

仅靠 sleep(1)(如答案所提)虽能轻微缓解服务端限流,但对解决 PHP 总执行超时问题效果有限——1 秒延迟无法显著降低累计耗时。真正有效的策略是:

  1. 显式限制单次请求最大等待时间(防止单次卡死)
  2. 为循环添加可控暂停(降低并发压力,辅助服务端负载均衡)
  3. 启用异步/分阶段处理思想(长期方案)

以下是优化后的安全循环示例:

for ($i = 0; $i <= 200; $i += 100) {
    $postData = [
        'start' => $i,
        'end'   => $i + 100
    ];

    $ch = curl_init('https://your-server.com/endpoint');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 45,          // ⚠️ 关键:强制单次请求最多等 45 秒
        CURLOPT_CONNECTTIMEOUT => 10,          // 连接超时设为 10 秒
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
        CURLOPT_POSTFIELDS     => json_encode($postData)
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($response === false) {
        $error = curl_error($ch);
        error_log("cURL failed at offset {$i}: {$error}");
        echo "Request {$i} failed.\n";
        continue;
    }

    // 可选:每轮后休眠 2–5 秒,减轻目标服务器压力(尤其面对无速率限制的共享环境)
    usleep(2000000); // 等待 2 秒(比 sleep(1) 更精细)

    echo "Batch [{$i}, " . ($i + 100) . "] completed. HTTP {$httpCode}\n";
}

? 关键注意事项

  • CURLOPT_TIMEOUT 是救命参数:它独立于 PHP 的 max_execution_time,专用于约束单个 cURL 请求的最长等待时间,防止某次请求因网络或服务端卡死拖垮整个脚本。
  • 不要依赖 sleep() 治本:sleep(1) 对总耗时影响微乎其微(2 次仅 +2s),且无法解决单次请求过长的问题;应优先设置 CURLOPT_TIMEOUT + 合理 CURLOPT_CONNECTTIMEOUT。
  • 服务端也需配合优化:如你控制目标接口(Destination),建议将耗时逻辑拆分为队列任务(如使用 Redis + Worker),返回即时响应(如 {"status":"accepted","job_id":"abc123"}),再通过轮询或回调获取结果——这才是应对长任务的生产级方案。
  • 浏览器执行 ≠ 后台作业:当前代码在浏览器中直接运行,意味着用户需持续等待至脚本结束。如需处理更大数据集,务必迁移到 CLI 模式(支持更长超时)或使用 AJAX 分页+前端轮询。

总之,PHP 循环中的多次 cURL 请求会线性累加执行时间,这是语言运行机制决定的,无法绕过。唯一稳健路径是:设限(cURL timeout)、降频(pause)、分流(异步化)