无法进行渐进式渲染

unable to do progressive rendering

几年前,我在以前的工作中编写了 CGI 程序,这些工作依赖于渐进式渲染,因为这些 CGI 程序可能需要很长时间(分钟)到 运行,大约每秒产生一行输出。我发现今天,即使是最简单的例子,我也无法实现渐进式渲染。

我看到很多关于这个主题的建议,关于在哪里放置 CSS、脚本等。但是,下面的简单示例有 none 个。

我没看到浏览器有任何影响渐进式渲染的选项。我已经在几个 systems/devices 上用几个浏览器(chrome、firefox、opera)试过了,结果都一样。

下面是一个简单的示例,我希望每 2 秒生成一些输出,但它会在整个文档完成时呈现。 我是否漏掉了一些明显的东西?

#!/usr/bin/env perl

select(STDOUT); $| = 1;     # don't buffer stdout

print "Content-Type: text/html\; charset=ISO-8859-1\n\n" ;
print "<html> <head> <title> Testing </title> </head> <body>\n" ;

my $message = "<code>" .
    "Why doesn't this render immediately? <br>\n" x 5 .
    "</code>\n" ;

for ( my $i=0 ; $i < 5 ; $i++ ) {
    print "$message\n" ;
    sleep(2) ;
}
print "</body></html>\n" ;

您还需要您的网络服务器将 CGI 脚本 运行 保持足够长的时间。默认的 Apache 有 1 分钟 timeout

您已经使用 $_ 关闭了缓冲,这很好。您无法从脚本中获得更多控制权。连接需要保持打开状态,即使您想进行分块传输,这在您的示例中并不是真正需要的。

是服务器过一会就关机了。一旦连接断开,网络服务器就不会通过网络发送您的响应的其余部分,因为该连接已断开并且 CGI 句柄已分离,因此没有任何内容会读取您的输出以传递它。

结论:将超时设置为更高的值。

轶事:我曾经在一个超时设置为大约一个小时的系统上工作,其中基于 CGI 的后台应用程序对巨大的 MySQL 数据库进行大型数据库查询,并且需要很长时间。使用该工具的人通常会启动它然后去喝咖啡或吃午饭。

您的网络服务器可能正在缓冲响应。 $| = 1;STDOUT 设置为每次 print 时自动刷新,消除 脚本 中缓冲的影响,但您还需要考虑在您的 网络服务器 .

中发生的缓冲

没有刷新缓冲区的命令或字符序列,但您可以简单地发送足够数量的数据来填充缓冲区,以便它自行刷新。

只是发送无关紧要的内容,比如一堆 spaces:

print " " x 1024 * 8;

您需要发送多少数据取决于您的网络服务器中配置的缓冲区大小。典型的缓冲区大小为 4KiB 或 8KiB,但请注意,如果您的服务器对脚本的响应进行 gzip 压缩,那么您将需要打印更多(可能大约 8MiB space 个字符)以填充服务器的缓冲区,因为缓冲区将填充压缩响应。

当然,您也可以只禁用服务器中的缓冲。你如何做到这一点取决于网络服务器。对于 nginx,请查看 X-Accel-Buffering.

ccm 的回复对我没有用,但它让我走上了正确的轨道来找到问题。解决方案是将以下内容添加到我的 Apache 配置中:

SetEnvIfNoCase Request_URI \.cgi$ no-gzip dont-vary

这是我从 Prevent output buffering with PHP and Apache

中找到的

在尝试@ccm 的建议时,缓冲区大小似乎是 1K,这对我来说没问题。

非常感谢@ccm 让我走上了正确的道路!