如何从Perl CGI脚本中不断通知用户进度?

时间:2009-10-29 17:26:06

标签: perl apache cgi

我将这个Perl脚本放在我的Apache服务器的cgi-bin文件夹中:

#!/usr/bin/perl 
use strict;
use warnings;

$| = 1;

print "Content-type: text/html\r\n\r\n";
print "Hello there!<br />\nJust testing .<br />\n";

my $top = 5;
foreach (1..$top) {
    print "i = $_<br />\n";
    sleep 1;
}

我想在这里实现的是逐步更新网页以向用户显示更新状态。然而,我实际上得到的是在延迟5秒之后的整个输出。

有什么办法可以编写一个能够不断通知用户进度的脚本吗?我有一个脚本需要很长时间才能完成,我希望能够实时看到它的进度,而不是完整的脚本。

我还尝试将autoflush模式设置为off($ | = 0),但即便如此也没有。

6 个答案:

答案 0 :(得分:5)

Randal Schwartz在Watching long processes through CGI中展示了更好的方法。

那就是说,说谎的内容类型无济于事。以下脚本完全按照您希望它在使用Apache 2.2的Windows XP上执行的操作(因为最后一行输出需要十秒钟):

#!/usr/bin/perl

use strict;
use warnings;

use CGI qw(:cgi);

print header('text/plain');

$| = 1;

print "Job started\n";

for ( 1 .. 10 ) {
    print "$_\n";
    sleep 1;
}

现在,如果您要发送HTML,您无法避免这样的事实,即大多数浏览器都会等到他们认为已经足够开始呈现的页面。

答案 1 :(得分:4)

您希望实现的目标是什么 - 浏览器通常会渲染到目前为止收到的内容,即使它不是完整的文档,只要有足够的标记就可以呈现任何内容。我想知道为什么你使用\r\n作为某些输出而只使用\n作为其他输出 - 你应该保持一致并始终使用\n。此外,您指定的是text / html的内容类型,但未在内容之前提供任何html标题(<html><title></title><body>)。

但是,执行此操作的“现代”方法是立即返回页面输出,但稍后将要更新的部分保留为空<div>元素。然后,您可以使用javascript(通过AJAX请求)更新该元素的内容。

答案 2 :(得分:2)

假设您使用的是比1.3更新的Apache版本,这应该可行。否则,你必须将你的脚本变成一个NPH(无解析标题)CGI,这意味着它的文件名应该以{{1​​}}为前缀,它应该输出完整的HTTP标题,例如。

nph-

请参阅(有点旧)Apache FAQ了解更多信息

答案 3 :(得分:2)

要查看您的脚本是否正常工作,请尝试使用命令行工具以避免与浏览器混淆。例如,curl将在收到数据后立即输出。

如果您正在做的事情是出于重要目的,我不会使用您当前的方法。如果脚本需要很长时间才能运行,请将其分解到后台(info here)并使用进度更新文件或数据库。然后,您可以使用自动刷新(JavaScript或META-REFRESH)iFrame来显示进度。您也可以使用AJAX,但这需要更多参与。

答案 4 :(得分:0)

将内容类型设置为text / plain时,它是否符合您的期望?也许浏览器中的HTML解析会导致输出延迟,因为您实际上并没有输出有效的HTML? (没有&lt; html&gt;或&lt; body&gt;标签)

答案 5 :(得分:0)

通过禁用该特定虚拟主机的Deflate模块,它对我有用。

SetEnv no-gzip 1

我猜你也可以使用.htaccess文件获得相同的结果。

相关问题