1

几年前,我在以前的工作中编写了依赖渐进式渲染的 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" ;
4

3 回答 3

2

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

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

只需发送无关紧要的内容,例如一堆空格:

print " " x 1024 * 8;

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

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

于 2016-12-31T20:27:31.113 回答
1

ccm 的回复对我不起作用,但它让我找到了问题所在。解决方案是将以下内容添加到我的 Apache 配置中:

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

我从使用 PHP 和 Apache 防止输出缓冲中发现的

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

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

于 2017-01-01T11:47:15.150 回答
0

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

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

是服务器在一段时间后将其关闭。一旦连接消失,网络服务器就不会通过线路发送您的剩余响应,因为该连接已经消失并且 CGI 句柄已分离,因此没有任何内容可以读取您的输出来传递它。

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

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

于 2016-12-31T10:23:14.677 回答