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; の後。null バイトを送信すると、ブラウザーは強制的に接続を終了します。また、Server::early_close() の前に ob_start() があると仮定していますか? そうでない場合は、ob_get_length が適切に機能するために必要です。

于 2013-10-04T16:32:53.193 に答える
1

これまでのコメントに基づいて、現在のソリューションをページ読み込み時の AJAX リクエストに置き換えることをお勧めします。接続を早期に閉じてサーバーで処理を続行する代わりに、通常どおりに応答を提供し、AJAX 要求を追加して、ページがクライアントに読み込まれた後に追加の処理を追加します。これにより、余分な出力の問題が完全に解消され、成功/失敗のメッセージをユーザーに送信することもできます。

もう 1 つの解決策は、作業をテーブルまたはメモリのキューに入れ、cron を設定してバックグラウンドで処理することです。

于 2013-10-07T15:54:45.663 に答える