我在cgi中有这段代码。
#!/usr/bin/perl
print "content-type: text/html \n\n";
print "<html><head><style>div.section{ font-size: 12px; border: 1px solid #999999; background-color: #EFEFEF; margin: 10px 15px;}p{ font-family: \"Arial\", \"Helvetica\", \"sans-serif\"; font-size: 14px; color: #444444; line-height: 30px; margin: 0 10px 0 10px; padding: 0 0 6px 0; text-align: center;}</style></head><body><div class=\"section\"><p>";
print "<b>YAMJ successfully updated your movie collection</b>";
print "</p><b>YAMJ output:</b><br>";
print "<pre>";
my $status = system("/usr/local/YAMJ/run.sh");
print "</pre>";
print "</div></body></html>";
该代码由MissileHugger为Synology中的YAMJ创建。事情是每次用户在synology上打开应用程序时,它只会在脚本执行其操作时为您提供空白页。
我想知道,有没有办法输出当时脚本正在做什么的实时数据进度?与我们安装Windows软件时类似,状态显示正在复制的文件等。
任何人都知道我是否可以这样做?
抱歉我的英语很差。
答案 0 :(得分:1)
这不容易做到。原因:HTTP是无状态的,浏览器只有在完全加载后才会呈现页面。
SERVER COMMUNICATION CLIENT
+------------+ +---------+
| Rendezvous | <----------- | Client |
+------------+ get status | Browser |
^ via | |
| write javascript | |
| status | |
+------------+ invoke | |
| Process | <----------- | |
+------------+ +---------+
以下是您可以使用的算法:
客户端浏览器请求CGI脚本。这开始了一个漫长的过程。它会向浏览器返回唯一的会话ID
长时间运行的进程会不断重写具有其状态的集合文件。
客户端浏览器轮询ID指定的rendezvous文件,并使用javascript更新网页。 HTML5有一个<progress>
meter元素,您可以使用它。
会话结束后,文件将从服务器文件系统中删除。
在最简单的情况下,您将浏览器指向一个连续重写的页面,并指示浏览器每隔几秒重新加载该页面。在AJAX时代,这基本上已经过时了。通过javascript加载内容将更加顺畅,并允许通过JSON传输复杂状态,例如:
{ "status": 0.4,
"comments": ["loaded a file",
"doing really hard math",
"almost finished - just a moment please"]}
而不是纯文本
Status: 40%
让服务器将这些事件推送到浏览器会非常优雅,但是,我不知道如何做到这一点。
答案 1 :(得分:0)
很棒的代码。非常感谢你的解决方案。我在过去的3天里一直在研究这个问题..
这是我更新脚本以使用我的程序所做的。
#!/usr/bin/perl
$|++; #This is needed to disable buffering
print "Content-type: text/html\r\n";
# This header is a quick hack which denies browser to gzip/deflate your output
print "Content-Encoding: plain\r\n\r\n";
&load_buffer; #This keeps the browser window printing progress as it's running
for ($i = 1; $i < 11; ++$i)
{
print "$i<br>\n";
sleep(1);
}
子程序
sub load_buffer {
my $cmd = qq{perl -e "\$|++; print ' ' and sleep(1) for 1..1"};
open my $PROC, '-|', $cmd or die $!;
while (sysread $PROC, $buffer, 1) { print "<!-- Browser shoudln't cache this chunk ", ' ' x 1000, "-->\n";}
}
答案 2 :(得分:-1)
您需要启用STDOUT
文件句柄的自动刷新才能实现此目的。
基本上,将以下代码放在脚本的顶部(在shebang之后)应该有所帮助:
$|++;
请访问previous answers on autoflush question了解有关autoflush的详细信息。
以下oneliners可以向您展示不同之处:
perl -e "$|++; print '#' and sleep(1) for 1..10"
perl -e "print '#' and sleep(1) for 1..10"
P.S。:如果你在终端中运行/usr/local/YAMJ/run.sh,我想你可以看到ASCII进度条。
UPD:
这应该有效,但是:
因此,您必须执行一些额外的工作:
#!/usr/bin/perl
$|++;
print "Content-type: text/html\r\n";
# This header is a quick hack which denies browser to gzip/deflate your output
print "Content-Encoding: plain\r\n\r\n";
print "<html><body><h1>Start</h1>\n";
my $cmd = qq{perl -e "\$|++; print '#' and sleep(1) for 1..100"};
# Start your command, read it's output byte by byte
# and send it to the browser with a 1000+ bytes long comment
# which should prevent browser from caching just a single character
open my $PROC, '-|', $cmd or die $!;
my $buffer;
while (sysread $PROC, $buffer, 1) {
print $buffer;
print "<!-- Browser shoudln't cache this chunk ", ' ' x 1000, "-->\n";
}
print "<h1>Done</h1></body></html>";