HTTP2 и продолжение выполнения PHP

При запуске PHP, и вы хотите, чтобы он немедленно возвратил HTML в браузер, закрыл соединение (ish) и затем продолжил обработку...

Следующее работает, когда соединение HTTP/1.1, но не при использовании Apache 2.4.25, с mod_http2 включен, и у вас есть браузер, который поддерживает HTTP/2 (например, Firefox 52 или Chrome 57).

Что происходит, Connection: close Заголовок не отправлен.

<?php

    function http_connection_close($output_html = '') {

        apache_setenv('no-gzip', 1); // Disable mod_gzip or mod_deflate

        ignore_user_abort(true);

        // Close session (if open)

        while (ob_get_level() > 0) {
            $output_html = ob_get_clean() . $output_html;
        }

        $output_html = str_pad($output_html, 1023); // Prompt server to send packet.
        $output_html .= "\n"; // For when the client is using fgets()

        header('Connection: close');
        header('Content-Length: ' . strlen($output_html));

        echo $output_html;

        flush();

    }

    http_connection_close('<html>...</html>');

    // Do stuff...

?>

Для похожих подходов к этой проблеме, см.:

  1. закрыть соединение рано
  2. Продолжить обработку после закрытия соединения
  3. Продолжить php скрипт после закрытия соединения

И почему connection заголовок удален, документация для nghttp2 библиотека (как используется Apache) заявляет:

https://github.com/nghttp2/nghttp2/blob/master/doc/programmers-guide.rst

HTTP/2 prohibits connection-specific header fields. The 
following header fields must not appear: "Connection"...

Так что, если мы не можем сказать браузеру закрыть соединение через этот заголовок, как нам заставить это работать?

Или есть другой способ сообщить браузеру, что у него есть все для ответа HTML, и что он не должен продолжать ждать поступления новых данных.

2 ответа

Решение

Как вернуть HTTP-ответ пользователю и возобновить обработку PHP

Этот ответ работает только тогда, когда веб-сервер общается с PHP через FastCGI протокол.

Чтобы отправить ответ пользователю (веб-сервер) и возобновить обработку в фоновом режиме, без участия вызовов ОС, вызовите fastcgi_finish_request() функция.

Пример:

<?php

echo '<h1>This is a heading</h1>'; // Output sent 

fastcgi_finish_request(); // "Hang up" with web-server, the user receives what was echoed

while(true)
{
    // Do a long task here
    // while(true) is used to indicate this might be a long-running piece of code
}

На что обращать внимание

  • Даже если пользователь получает вывод, php-fpm Дочерний процесс будет занят и не сможет принимать новые запросы, пока не завершит обработку этой длительной задачи.

Если все доступно php-fpm дочерние процессы заняты, тогда ваши пользователи будут испытывать зависание страницы. Используйте с осторожностью.

nginx а также apache оба сервера знают, как бороться с FastCGI протокол, поэтому не должно быть никаких требований по обмену apache сервер для nginx,

Вы можете обслуживать свои медленные PHP-скрипты через HTTP/1.1, используя специальный поддомен.

Все, что вам нужно сделать, это установить второй VirtualHost, который отвечает HTTP/1.1, используя директиву Apache Protocols: https://httpd.apache.org/docs/2.4/en/mod/core.html

Большим преимуществом этой техники является то, что ваши медленные сценарии могут отправлять некоторые данные в браузер задолго до того, как все остальное было отправлено через поток HTTP/2.

Другие вопросы по тегам