我在尝试使用php输出压缩时遇到问题,我已经搜索了许多小时,但仍然没有任何线索...

让我们看一个简单的脚本:

<?php
$response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh";

if(function_exists('ob_gzhandler'))
{
  ob_start('ob_gzhandler');
}
else {
  ob_start();
}


echo $response;
ob_end_flush();

这是我在互联网上发现的一种方法,它曾经对我有用……但现在已经不复存在了(我也不知道为什么)。

如果我在调用此脚本时查看http header :

要求 :
Host: 192.168.51.191
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cache-Control: max-age=0

回复 :
Connection: Keep-Alive
Content-Type: text/html
Date: Tue, 26 Jan 2016 15:19:07 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.9 (Win64) OpenSSL/1.0.1g PHP/5.5.12
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: PHP/5.5.12

您会看到响应未压缩(Firebird给了我0.06ko响应),并且服务器使用分块编码发送了响应。

我尝试了另一种发送压缩响应的方法:
<?php
    $response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh";
    $replyBody = gzencode($response, 9, FORCE_GZIP);
    header("Content-Encoding: gzip");
    echo $replyBody;

响应 header 如下(请求 header 始终相同):

回复 :
Connection: Keep-Alive
Content-Type: text/html
Date: Tue, 26 Jan 2016 15:29:01 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.9 (Win64) OpenSSL/1.0.1g PHP/5.5.12
Transfer-Encoding: chunked
X-Powered-By: PHP/5.5.12

如您所见,这基本上与第一种方法的行为相同。

然后,如果我尝试这样:
<?php
$response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh";
$replyBody = gzencode($response, 9, FORCE_GZIP);
echo $replyBody;

我收到的内容看起来像是压缩的响应(随机字符),输出大小为0.03ko。

这里是一个相应的响应http header :
Connection: Keep-Alive
Content-Length: 31
Content-Type: text/html
Date: Tue, 26 Jan 2016 15:32:46 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.9 (Win64) OpenSSL/1.0.1g PHP/5.5.12
X-Powered-By: PHP/5.5.12

它使我认为压缩部分在正常工作,因为输出大小已减小(由于浏览器无法知道它是压缩内容,因此显然不可读)。

那是我迷路的地方...

如果我理解正确,当我手动发送压缩数据(使用gzencode)时,如果我设置标题“Content-Encoding:gzip”,则webserver/php似乎先将其解压缩,然后再将其发送到浏览器中?这怎么可能 ?

以及为什么将其作为“块状”数据发送而不是设置Content-Length header ?

我尝试在响应中手动设置Content-Length;它没有任何改变(它不会出现在响应头中,我仍然会有一个“块状”响应。

我发现某个地方必须发送“Content-Length” header ,然后再发送其他数据或 header ,以避免“分块”响应,我尝试了一下,但结果仍然相同。

我以为在我的php测试脚本的开头可能是BOM字符有问题,但是它没有BOM编码就保存在UTF-8中,所以我不认为这是问题。

我的开发计算机上(使用wampserver)和生产环境(IIS)中都存在此问题,以前它在两台服务器上均有效。

我在使用多个浏览器时遇到了这个问题,并且检查了我之前用fiddler编写的响应大小。

有人知道问题可能在哪里吗?

提前致谢

最佳答案

如果我是你,我将通过以下 list 。

1 。检查是否安装了zlib扩展名。
ob_gzhandler needs the zlib扩展名可以正常工作。没有它,它只会默默地退回到默认设置。

2 。确认不要在zlib.output_compression中启用 php.ini

here所述,即使zlib.output_compression优于ob_gzhandler(),您也可以而不是同时使用两者。这样您的代码就变成了..

if (extension_loaded('zlib') && !ini_get('zlib.output_compression')){
    ob_start('ob_gzhandler');
}

3 。检查标题是否已经发送,例如。在此之前输出了一些东西
ob_start(ob_gzhandler)这将阻止如此检测到压缩输出。例如。在代码中的<?phpecho之前有一些字符。

4 。确保除了apache( mod_deflate )中的gzip压缩之外,还没有使用上述所有内容。
这只会导致输出为 double gzip压缩的,这很可能会使混淆浏览器的

关于PHP-输出压缩问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35018386/

10-12 12:50
查看更多