如何协调 gzip 压缩和 header 的刷新 index.php

How to reconcile gzip compression and the flushing of the header of index.php

我有一个相当大的 index.php 文件(大约 500kB),其中存在大量逻辑和数据库查询(而发送到客户端的 index.php 大约为 200kB)。
我想做的是首先使用 gzip 压缩文件,我只需在我的 .htaccess 文件中添加 SendOutputFilter 即可。现在,由于服务器处理的文件很大,TTFB 可能需要一段时间,因此我想在查看查询之前将文件的 header 发送给用户,以便浏览器将发现图像,css 和 js(它们也相当大)并且将开始下载而不是闲置等待整个 index.php 在服务器上处理(我想要像 Google 搜索会。它会在整个页面加载(并且页面被压缩)之前开始下载 png。
我做了一些查询,但找不到任何直接的解决方案。我发现要么我禁用 gzip 并使用 flush,要么使用 gzip 但不使用 flush。
但正如您在我的案例中看到的那样,我需要两者,而且我知道这可以通过某种方式完成。可能有一些解决方法。
这就是大型现代网站已经做到的,所以我想知道怎么做。

这并没有解决 GZIP 和刷新的问题,而是 PHP 针对您有关预加载的问题量身定制的脚本和页面设计 css、html 等

您可能需要考虑将 index.php 工作负载分配给两个脚本,首先加载 html 用于显示目的,然后使用 ajax 异步请求 "heavier" 任务,随后更新屏幕的某些部分。 这将允许 CSS 和所有其他人先完成他们的工作,然后是更长的 运行 任务,以便稍后显示他们的结果。

要完成此操作,请使用包含基本网页 html 和显示逻辑的 "lightweight" index.php 文件,以及 event/trigger 之类的 $(window).load(function(){ //ajax call to heavier heavy_index.php script and screen updating from response })让页面完全呈现,然后在加载后调用更重的东西。

这给出了一个简单的例子:

index.php

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="/my_css.css">

        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
        <script type="text/javascript">

            $(window).load(

                function () {
                    alert("About to load more content");

                    $.ajax({
                        url: "/heavy_index.php",
                        success: function (html_data) {
                            $("#content_loaded_later").html(html_data);
                        }
                    });
                });

        </script>
    </head>

    <body>
        <div class='content_initial'  ><span>Content initially loaded</span></div>
        <div class='content_later' id='content_loaded_later'>loading...</div>
    </body>
</html>

重_index.php

<?php
echo "resulting content from heavier workload";
?>

my_css.css

.content_initial
{
border:1px solid red; width:120px; height:120px;
margin:10px;
}

.content_later
{
border:1px solid green; width:120px; height:120px;
margin:10px;
}

你可能还想看看这个postPreload CSS/Javascript without Execution

希望这对您有所帮助。

据我所知,在 Apache 中没有办法强制提前将内容输出到浏览器。然而,可以从 PHP 开始这样做。请注意,在 PHP 中,输出缓冲区可以分层,因此您可能需要....

while (ob_get_level()) ob_end_flush();

这将在不关闭标准输出的情况下将数据发送回 Apache。在没有其他并发症的情况下,这将触发对浏览器的分块响应。但是 mod_deflate 输出过滤器也缓冲数据 - DeflateBufferSize - 默认为 8kb。如果您的 (不是您的 HEADER!)大于此大小,它将位于缓冲区中,直到它被更多内容推出。您可以减小缓冲区的大小,也可以填充您的内容以填充它 - 实际上您应该使用这两种方法。

由于其他人已经说过这是不可能的(事实并非如此 - 试试吧)并描述了使用 Ajax 来加载页面,您可能想看看 PJAX. There are big adavantages 以使用这在非常 javascript 繁重的网站上。

幸运的是我错了。尽管 GZIP 需要在解压缩之前完全下载,但您不必只发送一个 chunk。您可以发送多个单独的 chunks,其中每个单独编码。

这意味着浏览器需要完整下载 chunk 一个,然后才能解压并开始解析 html。同时它正在下载chunk两个。

Progressive rendering via multiple flushes 是一篇很好的文章,解释了它是如何工作的。然而,它不是 PHP 处理的,而是 server/apache 处理的。

查看 How to make PHP generate Chunked response 以了解您需要完成的 PHP 部分。

要使 GZIP 正常工作与您的服务器设置方式有关,为了获得帮助,您最好的选择是 serverfault