Apache / PHP 输出缓存

7
我正在编写一个PHP脚本,动态生成大量(多MB)输出,但不知道预先的长度。我通过fwrite()直接写入php://output,并尝试了标准输出和使用Transfer-Encoding: chunked(根据需要编码块),但无论我尝试什么,浏览器都会等待所有数据被写入后才显示下载对话框。我已经尝试在头部和每个块之后使用flush(),但这也没有任何区别。
我猜测Apache正在缓存输出,因为浏览器通常在从服务器接收到几KB后显示。
有人有关于如何停止此缓存并在生成时将数据刷新到浏览器的想法吗?
谢谢, J

1
与其猜测 Apache 直到整个内容生成后才刷新,我建议使用 Wireshark 或类似工具来“查看”发送到浏览器的数据。如果需要减慢速度,请插入一些 sleep(1) 调用。(我怀疑 Apache 在单个套接字上维护数兆字节之前会刷新其缓冲区。) - sarnold
3
我猜测你在php.ini和/或apache配置中启用了GZIP压缩。在这种情况下,Apache始终会进行缓存。我没有找到避免这个问题的方法(除非禁用压缩),所以让我们看看其他人对此了解多少。这可能是一个适合在serverfault.com上询问的问题... - BlaM
@sarnold - 当我说我在猜测时,这是一种有根据的猜测,因为我一直在通过 Fiddler 跟踪请求,并且在下载对话框出现之前没有看到任何响应,所以我非常自信它是在服务器端进行缓存。 @BlaM - 你绝对正确地说 GZIP 已启用,我没有考虑到这可能是一个原因,因为它是一种流压缩算法,但这可能是问题所在。我将尝试禁用此特定脚本并查看发生了什么。谢谢。 - JWood
@user290796,啊哈,那就不算是“猜测”了! :) 如果@BlaM是对的,也许你可以编写自己的Apache输出过滤器来发送定期FLUSH桶,以保持gzip的好处。(似乎在处理大文件时非常有用。) - sarnold
虽然我不是100%确定Fiddler在显示之前是否等待完整的输出,所以它有点猜测;)。实际上,输出的文件是一个ZIP文件,因此已经压缩,因此保留GZIP可能没有太大的好处,但输出过滤器可能是一个选项。我现在离服务器很远,无法尝试禁用GZIP,但我今天稍后会尝试一下。 - JWood
1个回答

1
首先,就像BlaM在他的评论中提到的那样,如果在PHP配置中启用了OutputBuffering,则它将无法正常工作,因此了解您的phpinfo()将非常有用。
接下来,请尝试使用存储在您的Web服务器上的大文件,使用readfile输出它。同时,请检查是否发送了正确的标头。有关如何使用readfile()和发送正确标头的提示,请参见:StackOverflow: How to force a file download in PHP 当您在进行这些操作时,请在脚本顶部调用ob_end_flush()ob_end_clean()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接