继续发送HTTP响应后处理的PHP继续发送HTTP响应后处理的PHP(continue proces

2019-05-06 10:19发布

我的脚本由服务器调用。 从服务器我会收到ID_OF_MESSAGETEXT_OF_MESSAGE

在我的剧本我会处理传入的文本,并产生响应使用参数: ANSWER_TO_IDRESPONSE_MESSAGE

问题是,我要送响应进来的"ID_OF_MESSAGE" ,但作为交付给我给我的消息处理将设置他的消息服务器(这意味着我可以给他针对这一ID),接收HTTP响应200之后。

其中一个解决方案是邮件保存到数据库,并提出一些cron的将被运行每分钟,但我需要立即生成响应消息。

有一些解决方案如何发送到服务器的HTTP响应200比继续执行PHP脚本?

非常感谢

Answer 1:

是。 你可以这样做:

ignore_user_abort(true);
set_time_limit(0);

ob_start();
// do initial processing here
echo $response; // send the response
header('Connection: close');
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();

// now the request is sent to the browser, but the script is still running
// so, you can continue...


Answer 2:

我见过很多答复就在这里,建议使用ignore_user_abort(true); 但是这个代码是没有必要的。 所有这样做是确保您的脚本继续执行在事件被发送之前的响应用户中止(通过关闭浏览器或按下Esc键停止请求)。 但是,这不是你在问什么。 你问一个后发送响应继续执行。 所有你需要的是以下几点:

    // Buffer all upcoming output...
    ob_start();

    // Send your response.
    echo "Here be response";

    // Get the size of the output.
    $size = ob_get_length();

    // Disable compression (in case content length is compressed).
    header("Content-Encoding: none");

    // Set the content length of the response.
    header("Content-Length: {$size}");

    // Close the connection.
    header("Connection: close");

    // Flush all output.
    ob_end_flush();
    ob_flush();
    flush();

    // Close current session (if it exists).
    if(session_id()) session_write_close();

    // Start your background work here.
    ...

如果你担心自己的后台工作将需要更长的时间比PHP的默认脚本的执行期限,然后坚持set_time_limit(0); 在顶部。



Answer 3:

如果你正在使用FastCGI处理或PHP-FPM,您可以:

session_write_close(); //close the session
fastcgi_finish_request(); //this returns 200 to the user, and processing continues

// do desired processing ...
$expensiveCalulation = 1+1;
error_log($expensiveCalculation);

来源: http://fi2.php.net/manual/en/function.fastcgi-finish-request.php



Answer 4:

我花了在这个问题上了几个小时,我来到这个功能,在Apache和Nginx的工作原理:

/**
 * respondOK.
 */
protected function respondOK()
{
    // check if fastcgi_finish_request is callable
    if (is_callable('fastcgi_finish_request')) {
        /*
         * This works in Nginx but the next approach not
         */
        session_write_close();
        fastcgi_finish_request();

        return;
    }

    ignore_user_abort(true);

    ob_start();
    $serverProtocole = filter_input(INPUT_SERVER, 'SERVER_PROTOCOL', FILTER_SANITIZE_STRING);
    header($serverProtocole.' 200 OK');
    header('Content-Encoding: none');
    header('Content-Length: '.ob_get_length());
    header('Connection: close');

    ob_end_flush();
    ob_flush();
    flush();
}

您可以将长处理之前调用这个函数。



Answer 5:

通过@vcampitelli有点修改答案。 不要以为你所需要的close头。 我看到在Chrome重复关闭头。

<?php

ignore_user_abort(true);

ob_start();
echo '{}';
header($_SERVER["SERVER_PROTOCOL"] . " 202 Accepted");
header("Status: 202 Accepted");
header("Content-Type: application/json");
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();

sleep(10);


Answer 6:

我使用PHP函数register_shutdown_function这一点。

void register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] )

http://php.net/manual/en/function.register-shutdown-function.php

编辑 :以上不工作。 看来我被一些旧的文档误导。 因为PHP 4.1 register_shutdown_function的行为已更改链接 链接



Answer 7:

我问这个问题拉斯姆斯·勒多夫2012年4月,理由是这些文章:

  • https://www.zulius.com/how-to/close-browser-connection-continue-execution/
  • 早关闭连接
  • http://php.net/manual/en/features.connection-handling.php

我提出了一个新的PHP的内置功能的开发,以通知没有进一步的输出(stdout上?),就会产生(这种功能可能采取的关闭连接的)平台。 拉斯姆斯·勒多夫回应:

见Gearman的 。 你真的不希望您的前端Web服务器做后端处理是这样的。

我可以看到他的观点,并支持他的意见对一些应用/加载场景! 然而,在一些其它情况下,从vcampitelli等的解决方案,是好的。



Answer 8:

对于一些模糊的原因,这些解决方案的使用MAMP PRO(Apache,MySQL和PHP)时工作。



Answer 9:

我有东西,可以压缩并发送响应,并让其他的PHP代码来执行。

function sendResponse($response){
    $contentencoding = 'none';
    if(ob_get_contents()){
        ob_end_clean();
        if(ob_get_contents()){
            ob_clean();
        }
    }
    header('Connection: close');
    header("cache-control: must-revalidate");
    header('Vary: Accept-Encoding');
    header('content-type: application/json; charset=utf-8');
    ob_start();
    if(phpversion()>='4.0.4pl1' && extension_loaded('zlib') && GZIP_ENABLED==1 && !empty($_SERVER["HTTP_ACCEPT_ENCODING"]) && (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') !== false) && (strstr($GLOBALS['useragent'],'compatible') || strstr($GLOBALS['useragent'],'Gecko'))){
        $contentencoding = 'gzip';
        ob_start('ob_gzhandler');
    }
    header('Content-Encoding: '.$contentencoding);
    if (!empty($_GET['callback'])){
        echo $_GET['callback'].'('.$response.')';
    } else {
        echo $response;
    }
    if($contentencoding == 'gzip') {
        if(ob_get_contents()){
            ob_end_flush(); // Flush the output from ob_gzhandler
        }
    }
    header('Content-Length: '.ob_get_length());
    // flush all output
    if (ob_get_contents()){
        ob_end_flush(); // Flush the outer ob_start()
        if(ob_get_contents()){
            ob_flush();
        }
        flush();
    }
    if (session_id()) session_write_close();
}


Answer 10:

还有一个办法及其值得考虑,如果你不想响应头篡改。 如果您在另一个进程启动一个线程调用的函数不会等待它的响应并返回给浏览器有定案HTTP代码。 您将需要配置并行线程

class continue_processing_thread extends Thread 
{
     public function __construct($param1) 
     {
         $this->param1 = $param1
     }

     public function run() 
     {
        //Do your long running process here
     }
}

//This is your function called via an HTTP GET/POST etc
function rest_endpoint()
{
  //do whatever stuff needed by the response.

  //Create and start your thread. 
  //rest_endpoint wont wait for this to complete.
  $continue_processing = new continue_processing_thread($some_value);
  $continue_processing->start();

  echo json_encode($response)
}

一旦我们执行$ continue_processing->开始()PHP不会等待这个线程的返回结果,因此只要rest_endpoint考虑。 它完成。

某些链接,以帮助并行线程

  • 一个如何使用PHP应用程序中的多线程
  • http://php.net/manual/kr/pthreads.installation.php

祝好运。



Answer 11:

在PHP的file_get_contents的情况下使用,连接关闭是不够的。 PHP仍然等待EOF魔女由服务器发送。

我的解决办法是阅读“内容长度:”

下面是示例:

response.php:

 <?php

ignore_user_abort(true);
set_time_limit(500);

ob_start();
echo 'ok'."\n";
header('Connection: close');
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();
sleep(30);

注意响应的“\ n”来收线,如果不是fget读而等待EOF。

read.php:

<?php
$vars = array(
    'hello' => 'world'
);
$content = http_build_query($vars);

fwrite($fp, "POST /response.php HTTP/1.1\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: " . strlen($content) . "\r\n");
fwrite($fp, "Connection: close\r\n");
fwrite($fp, "\r\n");

fwrite($fp, $content);

$iSize = null;
$bHeaderEnd = false;
$sResponse = '';
do {
    $sTmp = fgets($fp, 1024);
    $iPos = strpos($sTmp, 'Content-Length: ');
    if ($iPos !== false) {
        $iSize = (int) substr($sTmp, strlen('Content-Length: '));
    }
    if ($bHeaderEnd) {
        $sResponse.= $sTmp;
    }
    if (strlen(trim($sTmp)) == 0) {
        $bHeaderEnd = true;
    }
} while (!feof($fp) && (is_null($iSize) || !is_null($iSize) && strlen($sResponse) < $iSize));
$result = trim($sResponse);

正如你可以看到这个脚本dosent等待约EOF如果内容长度达到。

希望这将有助于



Answer 12:

我无法安装并行线程和既不是以前的解决方案为我工作。 我只发现了以下解决方案正常工作(参考: https://stackoverflow.com/a/14469376/1315873 ):

<?php
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 !
session_write_close(); // Added a line suggested in the comment
// Do processing here 
sleep(30);
echo('Text user will never see');
?>


Answer 13:

我知道这是一个古老的一个,但在这一点上可能是有用的。

这个答案我不支持实际的问题,但如何正确地解决这个问题。 希望它可以帮助其他人解决这样的问题。

我会建议使用RabbitMQ的或类似的服务,并使用运行后台工作量工人实例 。 有一个叫包amqplib对PHP这做所有的工作供你使用RabbitMQ的。

Pro的:

  1. 它的高性能高
  2. Nicly结构和维护
  3. 这是一个与工人是绝对的实例可扩展性

NEG的:

  1. RabbitMQ的,必须在服务器上安装,这可能是一些网络托管商的问题。


文章来源: continue processing php after sending http response