HTTP2 并继续 PHP 执行

HTTP2 and continuing PHP execution

当运行PHP,而你想让它立即returnHTML到浏览器,关闭连接(ish),然后继续处理.. .

以下内容在连接为 HTTP/1.1 时有效,但在使用 Apache 2.4.25、启用 mod_http2 并且您的浏览器支持 HTTP/2(例如 Firefox 52 或 Chrome 57)。

没有发送 Connection: close header。

<?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. close a connection early
  2. Continue processing after closing connection
  3. Continue php script after connection close

关于 connection header 被删除的原因,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"...

所以如果我们不能通过这个 header 告诉浏览器关闭连接,我们如何让它工作?

或者是否有另一种方式告诉浏览器它拥有 HTML 响应的所有内容,并且它不应该继续等待更多数据到达。

如何return HTTP 响应用户并恢复PHP 处理

此答案仅在网络服务器通过 FastCGI 协议与 PHP 通信时有效。

要向用户(Web 服务器)发送回复并在后台恢复处理,而不涉及 OS 调用,请调用 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 子进程都很忙,那么您的用户将遇到挂起页面。谨慎使用。

nginxapache 服务器都知道如何处理 FastCGI 协议,因此不需要将 apache 服务器换成 nginx .

您可以使用特殊的子域通过 HTTP/1.1 为您的慢速 PHP 脚本提供服务。

您需要做的就是使用 Apache 的协议指令设置第二个响应 HTTP/1.1 的 VirtualHost:https://httpd.apache.org/docs/2.4/en/mod/core.html#protocols

这项技术的最大优势在于,您的慢速脚本可以在其他所有内容通过 HTTP/2 流发送很久之后向浏览器发送一些数据。