多年前,我在先前依赖渐进式渲染的工作中编写了CGI程序,因为这些CGI程序可能需要很长时间(分钟)才能运行,每秒产生一行输出。我发现今天,即使用最简单的例子,我也无法进行渐进式渲染。
我已经看到很多关于这个主题的建议,关于在哪里放置CSS,脚本等等。但是,下面这个简单的例子没有。
我没有看到浏览器可以选择影响渐进式渲染的任何地方。我已经在几个具有多个浏览器(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" ;
答案 0 :(得分:2)
您的网络服务器可能正在缓冲响应。 $| = 1;
设置STDOUT
每次print
时自动刷新,消除脚本中缓冲的影响,但您还需要考虑缓冲正在发生的事情在您的网络服务器。
没有命令或字符序列来刷新缓冲区,但你可以简单地发送足够数量的数据来填充缓冲区,以便它自己刷新。
只需发送无关紧要的内容,就像一堆空格:
print " " x 1024 * 8;
需要发送多少数据取决于配置在Web服务器中的缓冲区大小。典型的缓冲区大小为4KiB或8KiB,但请注意,如果您的服务器gzips脚本的响应,那么您将需要打印更多(可能大约8MiB的空格字符),以填充服务器的缓冲区,因为缓冲区将填充压缩响应。
当然,您也可以在服务器中禁用缓冲。如何执行此操作取决于Web服务器。对于nginx,请查看X-Accel-Buffering。
答案 1 :(得分:1)
来自ccm的回复对我来说不起作用,但它让我找到了解决问题的正确方法。解决方案是将以下内容添加到我的Apache配置中:
SetEnvIfNoCase Request_URI \.cgi$ no-gzip dont-vary
我从Prevent output buffering with PHP and Apache
找到的在尝试@ccm建议时,看起来缓冲区大小为1K,这对我来说没问题。
非常感谢@ccm让我走上了正确的道路!
答案 2 :(得分:0)
您还需要您的网络服务器来保持CGI脚本运行足够长的时间。默认Apache有1分钟timeout。
您已使用$_
关闭缓存,这很好。脚本没有更多的控制权。连接需要保持打开状态,即使您想要进行分组传输,在您的示例中并不是真的需要。
服务器在一段时间后将其关闭。一旦连接消失,网络服务器就不会通过线路发送你的响应的剩余部分,因为连接已经消失并且CGI句柄被分离,所以没有任何东西正在读取你的输出以传递它。
结论:将超时设置为更高的值。
轶事:我曾经在一个超时设置大约一个小时的系统上工作,其中一个基于CGI的后台应用程序在一个庞大的MySQL数据库上进行大量的数据库查询,并且需要很长时间。使用该工具的人通常会开始使用咖啡或吃午饭。