在Apache中启用gzip压缩时,不会发送Content-Length?

我真的很感谢一些帮助理解这个Apache的行为。

我正在通过application / json中的iPhone Objective-C应用程序与PHP进行通信。 Gzip压缩在服务器上启用,并由客户端请求。

从我的.htaccess:

AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php application/json 

对于小的请求,Apache正在设置“Content-Length”标题。 例如(这些值是从头中的Objective-C中输出的):

 Connection = "Keep-Alive"; "Content-Encoding" = gzip; "Content-Length" = 185; <------------- "Content-Type" = "application/json"; Date = "Wed, 22 Sep 2010 12:20:27 GMT"; "Keep-Alive" = "timeout=3, max=149"; Server = Apache; Vary = "Accept-Encoding"; "X-Powered-By" = "PHP/5.2.13"; "X-Uncompressed-Content-Length" = 217; 

X-Uncompressed-Content-Length是我添加的一个头文件,设置为未压缩的JSONstring的大小。

正如你所看到的,这个请求非常小(217字节)。

以下是来自更大请求(282888字节)的标题:

 Connection = "Keep-Alive"; "Content-Encoding" = gzip; "Content-Type" = "application/json"; Date = "Wed, 22 Sep 2010 12:20:29 GMT"; "Keep-Alive" = "timeout=3, max=148"; Server = Apache; "Transfer-Encoding" = Identity; Vary = "Accept-Encoding"; "X-Powered-By" = "PHP/5.2.13"; "X-Uncompressed-Content-Length" = 282888; 

请注意,没有给出Content-Length。

我的问题:

  1. 为什么Apache没有发送更大请求的Content-Length?
  2. 设置“Contend-Encoding = gzip”的事实是否意味着即使我无法validation大小差异,gzip压缩仍然可以处理更大的请求。
  3. 有没有一种方法可以让Apache将这些较大请求的实际内容长度包括在内以更准确地向用户报告数据使用情况?

这个应用程序可以用于昂贵的数据计划,因此我希望向用户报告实际使用情况,而不是使用30-70%的夸大使用量(几百KB的额外听起来可能不是很多 – 但是这些计划可能花费1美元和每MB 10美元!)。

提前致谢。

除了Martin Fjordvalds回答:

仅当压缩文件大小大于DeflateBufferSize时,Apache才会使用分块编码。 因此,增加此缓冲区大小将防止服务器对较大文件使用分块编码,从而导致即使对于压缩数据也会发送内容长度。

更多信息可以在这里find: http : //httpd.apache.org/docs/2.2/mod/mod_deflate.html#deflatebuffersize

听起来像Apache正在做分块编码,这意味着它可以发送数据,因为它正在被压缩,而不是等待完整的响应被压缩。 这是相当标准的做法,但是我对Apache不太熟悉,不知道它是否可以被禁用。

好的,我设法解决了这个问题。 正如Martin F正确地指出的那样,Apache正在分块回应,所以内容大小不得而知。 对于很多人来说,这是可取的(页面加载速度更快)。 这是以无法报告下载进度为代价的。

对于那些真正想要报告下载进度的人,如果您使用Apache或PHP的自动gzip支持,那么您可以做的事情很less。 解决办法是手动完成。 这比听起来容易:

如果你发送整个文件,那么这是一个很好的例子,在PHP中强制一个块(与内容长度): http : //www.php.net/manual/en/function.ob-start.php #94741

如果您发送生成的数据,那么使用gzencode来编码您的数据,就像上面的示例一样。 一个先决条件是所有的输出数据都存储在一个variables中(如果需要缓冲,可以使用ob_start来获得帮助,然后获取缓冲区的内容)。

  // $replyBody is the entire contents of your reply header("Content-Type: application/json"); // or whatever yours is // checks if gzip is supported by client $pack = true; if(empty($_SERVER["HTTP_ACCEPT_ENCODING"]) || strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') === false) { $pack = false; } // if supported, gzips data if($pack) { header("Content-Encoding: gzip"); $replyBody = gzencode($replyBody, 9, FORCE_GZIP); } // compressed or not, sets the Content-Length header("Content-Length: " . mb_strlen($replyBody, 'latin1')); // outputs reply & exits echo $replyBody; exit; 

瞧!

自己做的另一个好处是可以设置压缩级别。 这对于我的移动应用程序是非常好的,因为我可以将其设置为最高的压缩级别(所以我的用户为数据支付更less的费用!) – 而服务器可能只使用中等压缩级别来实现更好的CPU /尺寸折衷。 压缩级别是我相信只有编辑httpd.conf(在共享主机上,我不能)才能改变。

所以我保留了我的DEFLATE .htaccess指令,除了我现在用上面的方法编码的application / json回复。

再次感谢Martin F,你给我的火花我需要解决这个:)