Wil*_*iss 14 php compression gzip apache-2.2
我真的很感激能帮助理解这种 Apache 行为。
我正在从应用程序/json 中的 iPhone Objective-C 应用程序与 PHP 通信。Gzip 压缩在服务器上启用,并由客户端请求。
从我的.htaccess:
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php application/json
Run Code Online (Sandbox Code Playgroud)
对于小型请求,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;
Run Code Online (Sandbox Code Playgroud)
X-Uncompressed-Content-Length是我添加的标头,设置为未压缩 JSON 字符串的大小。
如您所见,此请求非常小(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;
Run Code Online (Sandbox Code Playgroud)
请注意,没有给出 Content-Length。
我的问题:
此应用程序可用于昂贵的数据计划,因此我希望向用户报告实际使用情况,而不是 30-70% 的夸大使用情况(额外的几百 KB 听起来可能不多——但这些计划的成本可能在 1 美元之间每 MB 10 美元!)。
提前致谢。
小智 14
除了 Martin Fjordvalds 答案:
Apache 仅在压缩文件大小大于 DeflateBufferSize 时才使用分块编码。因此,增加此缓冲区大小将阻止服务器对较大的文件也使用分块编码,从而导致即使对于压缩数据也发送 Content-Length。
更多信息可在此处获得:http : //httpd.apache.org/docs/2.2/mod/mod_deflate.html#deflatebuffersize
听起来 Apache 正在执行分块编码,这意味着它可以在 gzip 压缩时发送数据,而不是等待 gzip 压缩完整响应。这是相当标准的做法,但我对 Apache 不够熟悉,无法说是否可以禁用它。
好的,我设法解决了这个问题。正如 Martin F 正确指出的那样,Apache 正在对回复进行分块,因此内容大小未知。对于许多人来说,这是可取的(页面加载速度更快)。这是以无法报告下载进度为代价的。
对于像我这样真正想要报告下载进度的人来说,如果您使用 Apache 或 PHP 的自动 gzip 支持,则无能为力。解决方法是手动完成。这比听起来容易:
如果您要发送整个文件,那么这是 PHP 中强制单个块(带有内容长度)的一个很好的示例:http : //www.php.net/manual/en/function.ob-start.php #94741
如果您要发送生成的数据,请使用 gzencode 对您的数据进行编码,就像上面的示例一样。先决条件是所有输出数据都存储在一个变量中(如果需要缓冲,然后获取缓冲区的内容,可以使用 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;
Run Code Online (Sandbox Code Playgroud)
瞧!
自己做的另一个好处是您可以设置压缩级别。这对我的移动应用程序非常有用,因为我可以设置为最高压缩级别(因此我的用户为数据支付的费用更少!)——而服务器可能只使用中等压缩级别以获得更好的 CPU/大小权衡。我相信压缩级别只有在您可以编辑 httpd.conf 时才能更改(在共享主机上,我不能)。
所以我保留了我的 DEFLATE .htaccess 指令,但我现在以上述方式编码的应用程序/json 回复除外。
再次感谢 Martin F,你给了我解决这个问题所需的火花:)