7

我很早就关闭了与客户端的连接:

static public function early_close( $output )
{
   ignore_user_abort(true);
   echo $output;

   // Disable gzip compression in apache, as it can result in this request being buffered until it is complete,
   // regardless of other settings.
   if (function_exists('apache_setenv')) {
       apache_setenv('no-gzip', 1);
   }

    // get the size of the output
    $size = ob_get_length();

    // send headers to tell the browser to close the connection
    header("Content-Length: $size");
    header('Connection: close');
    header("Content-Encoding: none"); // To disable Apache compressing anything

    // IF PHP-FM
    // fastcgi_finish_request();

    // flush all output
    if( ob_get_level() > 0 )
    {
        ob_end_flush();
        ob_get_level()? ob_flush():null;
        flush();
    }

    // if you're using sessions, this prevents subsequent requests
    // from hanging while the background process executes
    if( session_id() )
    {
        session_write_close();
    }
}

工作正常,但在此事件之后,如果某些脚本输出任何内容(通过回显或添加新标头),则脚本将从该点停止执行。
我试图在提前关闭后开始输出缓冲,然后将其丢弃,但它不起作用:

Server::early_close();
ob_start();
heavy_work();
ob_clean();

有任何想法吗?
使用 php 5.3.x

4

4 回答 4

2

执行此操作的经典代码是:

ob_end_clean();
header("Connection: close");
ignore_user_abort();              // optional ob_start();

echo ('Text the user will see');

$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush();                   // Strange behaviour, will not work
flush();                          // Unless both are called !

// Do processing here
sleep(30);

echo('Text user will never see');

否则,如果您想进行异步调用,我建议您阅读以下内容:PHP 中异步进程的方法

于 2013-10-07T00:24:57.547 回答
1

恕我直言,你不应该走这条路。Http 请求应尽可能短以提高可用性。

如果应该执行一些“繁重的处理”,您可以使用某种队列“调度”它。服务器上的一个单独的进程/守护进程可以从队列中提取这些作业来执行它们。然后,http 应用程序可以检查此类作业是否仍在等待处理/已启动/已完成。

有许多库可以帮助实现这一点:GearmanØMQRabbitMQ等。

Http 请求并不真正适合长操作,这就是为什么您在尝试这样做时会遇到各种问题的原因 :)

更新

如果您无法在服务器上使用库(如 Gearman 等),您可以构建自己的基于文件或数据库的队列,从应用程序中将“命令”推送到队列中,并让 cronjob 读取该队列并执行这些任务。

于 2013-10-04T15:54:51.360 回答
1

你需要一个 echo chr(0); 在 echo $output; 之后。发送空字节将强制浏览器结束连接。另外,我假设在 Server::early_close() 之前有一个 ob_start()?如果没有,您将需要它才能使 ob_get_length 正常工作。

于 2013-10-04T16:32:53.193 回答
1

根据您迄今为止的评论,我建议在页面加载时用 AJAX 请求替换您当前的解决方案。与其提前关闭连接并继续在服务器上处理,不如像往常一样提供响应并添加 AJAX 请求以在页面加载到客户端后添加任何其他处理。这完全消除了无关输出的问题,您还可以将任何成功/失败消息发送回用户。

另一种解决方案是将您的工作排在表或内存中,并设置一个 cron 在后台处理。

于 2013-10-07T15:54:45.663 回答