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...
?>
Для похожих подходов к этой проблеме, см.:
- закрыть соединение рано
- Продолжить обработку после закрытия соединения
- Продолжить 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.