복붙노트

HTTP 응답을 보낸 후 PHP 처리 계속

PHP

HTTP 응답을 보낸 후 PHP 처리 계속

내 스크립트는 서버에 의해 호출됩니다. 서버에서 ID_OF_MESSAGE 및 TEXT_OF_MESSAGE를 받게됩니다.

필자의 스크립트에서는 들어오는 텍스트를 처리하고 params : ANSWER_TO_ID 및 RESPONSE_MESSAGE를 사용하여 응답을 생성합니다.

문제는 내가 "ID_OF_MESSAGE"에 대한 응답을 보내고 있지만 처리 할 메시지를 보내는 서버가 HTTP 응답 200을받은 후 자신에게 전달 된 메시지를 설정한다는 것입니다.

해결책 중 하나는 메시지를 데이터베이스에 저장하고 매 분마다 실행될 일부 cron을 만드는 것이지만 즉시 응답 메시지를 생성해야합니다.

거기에 몇 가지 솔루션을 서버 HTTP 응답 200 보내고 PHP 스크립트를 계속 실행하는 것보다 있습니까?

정말 고마워

해결법

  1. ==============================

    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...
    
  2. ==============================

    2.ignore_user_abort (true)를 사용하여 제안하는 많은 응답을 여기에서 보았습니다. 그러나이 코드는 필요하지 않습니다. 이 모든 것은 브라우저가 닫히거나 요청을 중지하기 위해 escape 키를 눌러 사용자가 중단 된 경우 응답을 보내기 전에 스크립트가 계속 실행되도록합니다. 그러나 그것은 당신이 요구하는 것이 아닙니다. 응답이 전송 된 후 계속 실행을 요청하는 중입니다. 필요한 것은 다음과 같습니다.

    ignore_user_abort (true)를 사용하여 제안하는 많은 응답을 여기에서 보았습니다. 그러나이 코드는 필요하지 않습니다. 이 모든 것은 브라우저가 닫히거나 요청을 중지하기 위해 escape 키를 눌러 사용자가 중단 된 경우 응답을 보내기 전에 스크립트가 계속 실행되도록합니다. 그러나 그것은 당신이 요구하는 것이 아닙니다. 응답이 전송 된 후 계속 실행을 요청하는 중입니다. 필요한 것은 다음과 같습니다.

        // 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); 상단에.

  3. ==============================

    3.FastCGI 처리 또는 PHP-FPM을 사용하는 경우 다음을 수행 할 수 있습니다.

    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

  4. ==============================

    4.나는이 문제에 대해 몇 시간을 보냈고 Apache와 Nginx에서 작동하는이 함수를 사용했다.

    나는이 문제에 대해 몇 시간을 보냈고 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();
    }
    

    오랜 처리 전에이 기능을 호출 할 수 있습니다.

  5. ==============================

    5.@vcampitelli의 대답을 약간 수정했습니다. 가까운 머리글이 필요하다고 생각하지 마십시오. Chrome에서 중복 된 닫기 헤더를보고있었습니다.

    @vcampitelli의 대답을 약간 수정했습니다. 가까운 머리글이 필요하다고 생각하지 마십시오. 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);
    
  6. ==============================

    6.나는 2012 년 4 월 Rasmus Lerdorf에게이 기사를 인용하여이 질문을 던졌다.

    나는 2012 년 4 월 Rasmus Lerdorf에게이 기사를 인용하여이 질문을 던졌다.

    필자는 플랫폼에 추가 출력 (stdout에?)이 생성되지 않는다는 것을 알려주는 새로운 PHP 내장 함수를 개발할 것을 제안했습니다. (그러한 함수는 연결을 닫을 수 있습니다.) 라스무스 레르 도르프 (Rasmus Lerdorf)

    나는 그의 요점을 볼 수 있으며, 일부 응용 프로그램 / 로딩 시나리오에 대한 그의 견해를지지합니다! 그러나 일부 다른 시나리오에서는 vcampitelli 외의 솔루션이 좋습니다.

  7. ==============================

    7.어떤 확실하지 않은 이유로 MAMP PRO (Apache, MySQL, PHP)를 사용할 때 이러한 솔루션이 작동하지 않습니다.

    어떤 확실하지 않은 이유로 MAMP PRO (Apache, MySQL, PHP)를 사용할 때 이러한 솔루션이 작동하지 않습니다.

  8. ==============================

    8.나는 이것을 위해 register_shutdown_function 함수를 사용한다.

    나는 이것을 위해 register_shutdown_function 함수를 사용한다.

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

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

    편집 : 위의 작동하지 않습니다. 나는 오래된 문서들에 속아 넘어 갔다. register_shutdown_function의 동작이 PHP 4.1 링크 링크 이후로 변경되었습니다.

  9. ==============================

    9.응답 헤더를 변경하고 싶지 않은 경우에는 다른 접근 방법과이를 고려해 볼 가치가 있습니다. 다른 프로세스에서 스레드를 시작하면 호출 된 함수는 응답을 기다리지 않고 최종 HTTP 코드가있는 브라우저로 돌아갑니다. pthread를 구성해야합니다.

    응답 헤더를 변경하고 싶지 않은 경우에는 다른 접근 방법과이를 고려해 볼 가치가 있습니다. 다른 프로세스에서 스레드를 시작하면 호출 된 함수는 응답을 기다리지 않고 최종 HTTP 코드가있는 브라우저로 돌아갑니다. pthread를 구성해야합니다.

    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-> start ()를 실행하면 PHP는이 스레드의 반환 결과를 기다리지 않으므로 rest_endpoint가 고려됩니다. 끝났어.

    pthreads에 도움이되는 링크

    행운을 빕니다.

  10. ==============================

    10.php file_get_contents를 사용하는 경우 연결 닫기만으로는 충분하지 않습니다. PHP는 여전히 서버에 의해 보내 마녀를 기다립니다.

    php file_get_contents를 사용하는 경우 연결 닫기만으로는 충분하지 않습니다. PHP는 여전히 서버에 의해 보내 마녀를 기다립니다.

    내 솔루션은 'Content-Length :'를 읽는 것입니다.

    샘플은 다음과 같습니다.

    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"에 주목하고, wait eof 동안 읽은 fget이 아니라면.

    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);
    

    보시다시피,이 스크립트는 콘텐츠 길이에 도달하면 eof를 기다리지 않습니다.

    도움이되기를 바랍니다.

  11. ==============================

    11.압축 할 수 있고 응답을 보내고 다른 PHP 코드를 실행할 수있는 무언가가 있습니다.

    압축 할 수 있고 응답을 보내고 다른 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();
    }
    
  12. from https://stackoverflow.com/questions/15273570/continue-processing-php-after-sending-http-response by cc-by-sa and MIT license