让我们看一个简单的脚本:
<?PHP $response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh"; if(function_exists('ob_gzhandler')) { ob_start('ob_gzhandler'); } else { ob_start(); } echo $response; ob_end_flush();
这是我在互联网上找到的一种方法,它曾经为我工作……但不再是(而且我不知道为什么).
如果我在调用此脚本时查看http标头:
要求:
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响应),服务器使用chunked编码发送响应.
我尝试了另一种方法来发送压缩响应:
<?PHP $response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh"; $replyBody = gzencode($response,9,FORCE_GZIP); header("Content-Encoding: gzip"); echo $replyBody;
响应标头如下(请求标头始终相同):
回应:
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,FORCE_GZIP); echo $replyBody;
我收到的东西看起来像一个压缩响应(随机字符),输出大小是0.03ko.
这里有一个相应的响应http头:
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似乎在将其发送到浏览器之前UNZIP它?这怎么可能 ?
为什么它将其作为“分块”数据发送而不是设置Content-Length标头?
我试图在响应中手动设置Content-Length;它不会改变任何东西(它不会出现在响应标题中,我仍然会有一个“分块”响应.
我已经看到某个地方,我必须在发送其他数据或标题之前编写“Content-Length”标题以避免“chunked”响应,我尝试了它并且仍然有相同的结果.
我认为在我的PHP测试脚本开头可能存在BOM字符的问题,但它是以UTF-8保存而没有BOM编码所以我不认为这是问题所在.
我在我的开发计算机(使用wampserver)和生产环境(IIS)中遇到此问题,之前它在两台服务器上都有效.
我使用几个浏览器有这个问题,我检查了我之前用fiddler编写的响应大小.
有谁看到问题可能在哪里?
提前致谢
1.检查是否安装了zlib扩展.
ob_gzhandler needs the zlib扩展工作.没有它,它只是默默地回到默认设置.
2.确认您的PHP.ini中没有启用zlib.output_compression
.
如here所述,即使zlib.output_compression优于ob_gzhandler(),也不能同时使用它们.所以你的代码变成..
if (extension_loaded('zlib') && !ini_get('zlib.output_compression')){ ob_start('ob_gzhandler'); }
3.检查标头是否已经发送,例如.在之前得到了一些东西
ob_start(ob_gzhandler)这将防止压缩输出被检测到.例如.在<?PHP之前有一些字符或在代码中的某个地方有一个echo. 4.除了在apache(mod_deflate
)中进行gzipping之外,请确保您没有使用上述所有内容.这只会导致输出被双重压缩,这很可能会混淆浏览器.