126

私のスクリプトはサーバーによって呼び出されます。サーバーから と を受け取りID_OF_MESSAGEますTEXT_OF_MESSAGE

私のスクリプトでは、着信テキストを処理し、params:ANSWER_TO_IDRESPONSE_MESSAGE.

問題は、 incomming"ID_OF_MESSAGE"に応答を送信していることですが、処理するメッセージを送信するサーバーは、http 応答 200 を受信した後、彼のメッセージを配信済みとして設定します (つまり、その ID に応答を送信できることを意味します)。

解決策の 1 つは、メッセージをデータベースに保存し、毎分実行される cron を作成することですが、すぐに応答メッセージを生成する必要があります。

サーバーの http 応答 200 に送信し、php スクリプトの実行を続行する方法はありますか?

本当にありがとうございました

4

13 に答える 13

220

はい。あなたはこれを行うことができます:

ignore_user_abort(true);//not required
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();
fastcgi_finish_request();//required for PHP-FPM (PHP > 5.3.3)

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

die(); //a must especially if set_time_limit=0 is used and the task ends
于 2013-03-07T14:24:42.327 に答える
44

FastCGI 処理または PHP-FPM を使用している場合は、次のことができます。

session_write_close(); //close the session
ignore_user_abort(true); //Prevent echo, print, and flush from killing the script
fastcgi_finish_request(); //this returns 200 to the user, and processing continues

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

ソース: https://www.php.net/manual/en/function.fastcgi-finish-request.php

PHP の問題 #68722: https://bugs.php.net/bug.php?id=68772

于 2016-08-12T12:39:04.490 に答える
26

私はこの問題に数時間を費やし、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();
}

長い処理の前にこの関数を呼び出すことができます。

于 2017-02-15T09:23:37.837 に答える
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);
于 2015-06-03T00:42:12.690 に答える
4

これには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 の動作が変更されました

于 2015-05-18T11:00:07.350 に答える
2

php file_get_contents を使用する場合、接続を閉じるだけでは十分ではありません。php はサーバーから eof ウィッチが送信されるのをまだ待っています。

私の解決策は、「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);

eof の待機中に fget が読み取られない場合は、行を閉じることに応答する "\n" に注意してください。

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 について待機しません。

それが役立つことを願っています

于 2016-08-26T08:26:03.913 に答える
0

回答に加えて、JSON 文字列を応答として返しました。不明な理由で応答が切り捨てられていることを発見しました。問題の修正は、余分なスペースを追加することでした:

echo $json_response;
//the fix
echo str_repeat(' ', 10);
于 2021-10-06T06:40:14.240 に答える