PHP等待curl执行完成后返回

4

我有两个PHP文件,一个用于“重活”,另一个用于快速响应并将请求传递给“重活”文件,使得快速响应文件能够立即响应服务器请求(至少这是目标)。这个前提是Slack Slash命令需要一个即时的200状态码来告知用户命令正在运行。

<?php
echo("I want this text to reply to server instantly");
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$code = '200';

$curl = curl_init();
curl_setopt_array($curl, array(
  CURLOPT_URL => "http://myheavyliftingfile.php",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "datatobeusedbyheavylifter:data",
  CURLOPT_HTTPHEADER => array(
    "cache-control: no-cache",
    "content-type: application/x-www-form-urlencoded",
    "postman-token: 60757c65-a11e-e524-e909-4bfa3a2845fb"
  ),
));

$response = curl_exec($curl);
?>

似乎发生的情况是,我的响应/回显直到我的heavylifting.php curl完成才被发送到Slack,即使我希望我的响应立即发生,而重载过程本身是分开的。如何让一个PHP文件确认请求,在不等待长时间处理完成的情况下启动另一个文件上的进程并作出响应?
更新:
我不想同时运行多个curl,我只想执行一个curl,但不必等待它返回以便向Slack返回一条消息表示我已收到请求。我的curl将数据发送到执行繁重工作的其他php文件。如果这仍然是定义在重复中的相同问题,请随时再次标记它,我不会重新打开它。

1
你尝试过在启动curl语句之前刷新输出缓冲区吗?http://php.net/manual/en/function.ob-flush.php - ivanivan
嗨ivanivan,我刚试了清空缓冲区但没有效果。 谢谢@barmar,关于标记的重复问题,这将允许我同时进行多个curl请求,但它是否允许我在每个curl请求完成之前向服务器返回200?如果是的话,那么是一个重复问题,如果不是,那么我的问题可能略有不同。我不想创建多个curl并让它们同时执行,我希望在启动curl请求后立即返回,而不必等待它完成,因为我的其他php文件会处理它。 - Patrick Lambe
这只是同样事情的一个更简单的案例。在不等待多个请求完成的情况下执行多个请求和在不等待一个请求完成的情况下执行一个请求有什么区别? - Barmar
实际上,我看到了问题。那个解决方案使用线程,但我认为主脚本直到所有线程完成才会完成。因此,如果您不想等待,需要另一种解决方案。 - Barmar
谢谢Barmar,是的,我相信这就是我的问题,我不想等待,而是希望通过同时运行多个curl来节省时间。很抱歉第一次没有表达清楚。也许在PHP中我所寻找的不可能,但还是想确认一下。 - Patrick Lambe
显示剩余2条评论
1个回答

4
这种方法不起作用的原因是,PHP curl调用始终是同步的,而您的超时设置为30秒,远远超过了允许的3秒最大时间限制。
但是有一个解决方法可以让它起作用。您只需要进行以下小改动:
  1. 将curl超时设置为较小的值以确保第一个脚本在3秒阈值以下完成,例如将CURLOPT_TIMEOUT_MS设置为400,即定义为400毫秒的超时。

  2. 在第一个脚本中将CURLOPT_NOSIGNAL设置为1。这对于UNIX系统中的超时操作是必需的。

  3. 请确保在第一个脚本中忽略超时错误(CURL ERROR 28),因为您的curl应始终返回超时错误。

  4. 通过添加此行来确保第二个脚本不会被强制超时中止:ignore_user_abort(true);

有关完整示例,请参见此答案
P.S.:对于这种方法,您不需要任何缓冲区刷新。

非常有帮助,谢谢Erik,你的方法完美地解决了问题。谢谢。 - Patrick Lambe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接