【问题标题】:How to reconcile gzip compression and the flushing of the header of index.php如何协调 gzip 压缩和 index.php 标头的刷新
【发布时间】:2015-04-02 08:05:21
【问题描述】:

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

【问题讨论】:

  • 在我看来你优化错了。如果你的index.php 是 500kb 并且有很多逻辑,那么这并不意味着生成的 HTML 内容也很大。所有的逻辑都被丢弃了。您确定问题在于生成的 HTML 非常大而 GZIP 是解决方案吗?
  • 感谢您的评论,我知道原始 index.php 的大小由于逻辑原因很大,但在发送到用户浏览器时会变小(因为我们只发送输出而不发送 php 逻辑)。我说 500kB 是为了清楚地表明有相当多的逻辑要执行。实际上,当发送到浏览器时,文件大约为 200 kB。所以是的,我仍然需要 gzip。
  • 好的,当您使用 GZIP 时,它突然就像50 左右?就像大幅改进一样。因为这些天在正常连接上,200kb 几乎是即时的。但无论如何,你想要的都做不到。您也许可以开始“刷新”发送数据,但浏览器需要完整的内容才能解包并开始渲染并查看需要加载的其他文件
  • 看看谷歌搜索,这正是它的作用。它会压缩 html 并同时在请求到达他们的服务器后立即发送文件头(甚至在查看查询之前),如果您仔细查看(devTools)中的 10% 的 html下载其他文件,如 png start beign 并行下载。你怎么解释?这是因为浏览器不需要整个 html 来开始处理它,只要浏览器开始下载部分 html,它就会开始解析它并构造 DOM(并行)
  • 再试一次,仔细查看在整个html下载之前开始下载的.png文件

标签: php apache gzip flush


【解决方案1】:

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

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

为了完成这个开始,使用带有基本网页 html 和显示逻辑的“轻量级” index.php 文件,以及像 $(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>

heavy_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;
}

您可能还想查看此帖子Preload CSS/Javascript without Execution

希望这会有所帮助。

【讨论】:

  • 你的意思是我需要使用 AJAX 发送 html 的其余部分,然后在 JS 中完成 DOM 的构建?
  • 是的,您在 $(window).load() 事件中完成了最终文档 HTML 的构建,该事件在初始页面和 DOM 加载完成后触发。换句话说,在您使用 ajax 请求其余部分之前,您的 CSS 和初始 HTML 已经被渲染和显示。
  • @Core_dumped,在我的回答中为您添加了一个编码示例。
  • 感谢克里斯的示例。
【解决方案2】:

据我所知,Apache 无法强制将内容提前输出到浏览器。但是,可以从 PHP 执行此操作。请注意,在 PHP 中,输出缓冲区可以分层,因此您可能需要....

while (ob_get_level()) ob_end_flush();

这将在不关闭标准输出的情况下将数据发送回 Apache。在没有其他并发症的情况下,这将触发对浏览器的分块响应。但是 mod_deflate 输出过滤器也会缓冲数据 - DeflateBufferSize - 默认情况下为 8kb。如果您的

(不是您的 HEADER!)大于此大小,它将位于缓冲区中,直到被更多内容推出。您可以减小缓冲区的大小,并且可以填充内容以填充它 - 实际上您应该同时使用这两种方法。

由于其他人说这是不可能的(不是 - 尝试一下)并描述了使用 Ajax 加载页面,您可能想看看PJAX。有很大的adavantages 在非常重的 javascript 网站上使用它。

【讨论】:

    【解决方案3】:

    幸好我错了。尽管GZIP需要完全下载才能解压,但您不必只发送一个chunk。您可以发送多个单独的chunks,其中每个都单独编码。

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

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

    查看How to make PHP generate Chunked response 了解您需要执行的PHP 部分。

    要使GZIP 工作与您的服务器设置方式有关,您最好的选择是serverfault

    【讨论】:

    • 这就是我要说的。感谢您的链接。我会尝试实现它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    • 2015-12-13
    • 1970-01-01
    相关资源
    最近更新 更多