随机出现的 gzip 标头

Posted

技术标签:

【中文标题】随机出现的 gzip 标头【英文标题】:Randomly appearing gzip headers 【发布时间】:2014-02-28 03:41:21 【问题描述】:

我在共享主机环境中有一个长时间运行的脚本,它输出一堆 XML

有时(仅有时)我的输出中会出现一个随机的 GZIP 标头,并且输出将被终止。

例如

0000000: 3c44 4553 435f 4c4f 4e47 3e3c 215b 4344  <DESC_LONG><![CD
0000010: 4154 415b 1fc2 8b08 0000 0000 0000 03c3  ATA[............
0000020: b3c3 8b57 c388 c38c 2b28 2d51 48c3 8bc3  ...W....+(-QH...
0000030: 8c49 5528 2e48 4dc3 8e4c c38b 4c4d c391  .IU(.HM..L..LM..
0000040: c3a3 0200 c291 4464 c383 1900 0000 0d0a  ......Dd........

0000000: 3c2f 5052 4f44 5543 543e 0d0a 1fc2 8b08  </PRODUCT>......
0000010: 0000 0000 0000 03c3 b3c3 8b57 c388 c38c  ...........W....
0000020: 2b28 2d51 48c3 8bc3 8c49 5528 2e48 4dc3  +(-QH....IU(.HM.
0000030: 8e4c c38b 4c4d c391 c3a3 0200 c291 4464  .L..LM........Dd
0000040: c383 1900 0000 0d0a                      ........

0000000: 3c4d 4544 4941 5f55 524c 3e2f 696d 6167  <MEDIA_URL>/imag
0000010: 6573 2f69 6d70 6f72 7465 642f 7374 6f63  es/imported/stoc
0000020: 6b5f 7072 6f64 3235 3339 365f 696d 6167  k_prod25396_imag
0000030: 655f 3531 3737 3439 3436 302e 6a70 673c  e_517749460.jpg<
0000040: 2f4d 4544 4941 5f55 1fc2 8b08 0000 0000  /MEDIA_U........
0000050: 0000 03c3 b3c3 8b57 c388 c38c 2b28 2d51  .......W....+(-Q
0000060: 48c3 8bc3 8c49 5528 2e48 4dc3 8e4c c38b  H....IU(.HM..L..
0000070: 4c4d c391 c3a3 0200 c291 4464 c383 1900  LM........Dd....
0000080: 0000 0d0a                                ....

切换到 GZIP 似乎在任何特定时间 og 字节计数都没有命中,它可以在 1MB 数据之后或 15MB 之后

对应行编译的刀片模板如下

<DESC_LONG><![CDATA[<?php echo $product->display_name; ?>]]></DESC_LONG>

-

</PRICES>
</PRODUCT>
<?php foreach($product->models()->get() as $model): ?>

-

<MEDIA_URL>/images/imported/<?php echo $picture->local_name; ?></MEDIA_URL>

我束手无策,我尝试了以下方法:

在服务器上禁用 gzip。 在运行脚本之前运行while(ob_get_level()) ob_end_clean(); .htaccess 中,我尝试过SetEnv no-gzip 1SetEnv no-gzip dont-vary 及其各种排列方式。

当我访问其他页面时,没有出现 gzip 编码或标题,所以我认为这是输出大小或输出缓冲区的问题。

【问题讨论】:

这可能有用也可能没用,但我看到 gzip 流已经插入了一堆无关的“0xc3”字节,我想试着让它看起来像有效的 UTF-8 . 如果在控制台(CLI)中运行会发生这种情况吗?或者,如果您在 127.0.0.1 (localhost) 中获取脚本? 能否提供更大的虚假输出样本,从1fc2 8b08 字节开始? 系统输出在0000 0d0a之后终止 随机出现的标头听起来像是另一个请求或进程负责......太糟糕了,您在共享主机上 - 使得隔离和调试这样的问题相当困难。 【参考方案1】:

您终于找到这些标头的来源了吗?我是说apache还是php?

你可以用类似的东西模拟 xml 生成器 scipt:

echo file_get_contents('your_good_test.xml');

如果您看不到任何标题,我建议您调试您的 xml 生成器。您可以尝试在输出前调用header_remove();

如果您看到标题,则必须调试您的网络服务器。尝试通过重写规则禁用 apache 中的 gzip:

`RewriteRule . - [E=no-gzip:1]`

只要您有任何代理或平衡器(nginx、squid、haproxy),您就会自动获得更多的火线。

【讨论】:

【参考方案2】:

您的 gziping 与返回您的主要 xml 正文的服务器输出无关。否则整个 xml 都会被压缩。

这些方法有时会返回 GZIP,因为这些方法获取项目的源设置为支持 gzip,并且没有正确询问。

$product->display_name
$product->models()->get()
$picture->local_name

看看这些。 - 检查所有设置标头的位置的网络调用。 - 暂时禁用数据库连接的压缩(如果有)。

为所有可以返回二进制数据的位置添加 CDATA 标记,以避免主 xml 正文构建终止。等待带有 bin 数据的 xml,保存 bin 数据,解压缩并查看里面的内容。 :-)

【讨论】:

【参考方案3】:

这更像是一组cmets,但是对于评论框来说太长了。

首先,这很可能不是输出缓冲区问题。尽管&lt;![CDATA[]]&gt; 不在PHP 标记中,但这并不意味着它不会通过PHP 的输出缓冲区。需要明确的是,.php 文件中的任何内容都将放置在 PHP 输出缓冲区中。 .php 文件中的内容(包括静态内容)在 Apache 外部缓冲,然后在脚本完成时通过此缓冲区传递回 Apache。这意味着您的问题必须存在于代码本身,这是在不查看代码的情况下在黑暗中解决的问题。

我的建议:

1) 在脚本中进行搜索以查找 gz 函数的任何实例(gzcompress、gzdeflate、gzdecode 等)。如果内容大于特定大小,我已经看到脚本会压缩内容,然后在从数据库中获取内容时即时解压缩内容。如果是这种情况,您可能会处理错误的比较操作。简而言之,压缩和解压条件下的逻辑有点不对劲,所以它无法解压部分内容。

2) 在脚本中进行搜索以查看如何获取此数据。全部来自数据库吗?它是否来自流?有没有远程获取的?这些问题可能不会直接导致答案,但至关重要。可以安全地假设这些变量是在不应该压缩的情况下使用已经压缩的数据设置的。它需要知道压缩发生的位置/原因/方式,以便回答为什么没有被解压缩。

3) 它在一个系统上按预期工作但在另一个系统上按预期工作非常重要。我见过这种情况的唯一一次总是由于配置的差异。你的本地机器使用的是什么操作系统?本地数据库有什么区别(如果有的话),其中一个或另一个上可能缺少/存在哪些扩展,可能导致函数回退到两台不同机器上的不同过程。

编辑: 此外,这是一个很小的机会,但是您是否正在处理来自不同服务器的 SQL 转储的数据?您说它可以在您的本地主机上运行,​​但不能在其他主机上运行,​​所以我们知道您在处理两台机器。在某个时候有第三个吗?如果是这样,它可能是使用不匹配的压缩版本/形式进行压缩的,或者可能是编码问题。

【讨论】:

以上是关于随机出现的 gzip 标头的主要内容,如果未能解决你的问题,请参考以下文章

如何获得 gzip 压缩文件的随机访问

随机发生,预检响应缺少允许标头

python 随机的http标头

POST 的标头和正文之间的随机延迟

随机得到不存在“Access-Control-Allow-Origin”标头

即使在更改标头和 IP 之后,验证码也会使用请求。我是如何被跟踪的?