如何解决Perl CGI脚本问题?

时间:2010-01-29 20:43:26

标签: perl cgi

我有一个无效的Perl脚本,我不知道如何开始缩小问题范围。我该怎么办?


注意:我正在添加问题,因为我真的想在Stackoverflow中添加我非常冗长的答案。我在其他答案中保持外部链接,它值得在这里。如果你有什么要补充的话,不要羞于编辑我的答案。

8 个答案:

答案 0 :(得分:125)

答案 1 :(得分:10)

我认为CGI::Debug也值得一提。

答案 2 :(得分:8)

我想知道为什么没有人提到名为PERLDB_OPTS的{​​{1}}选项;虽然可以肯定的是,网络上的工作示例并不多(RemotePort中甚至没有提到RemotePort) - 而且我提出这个问题有点问题,但是这里有一个问题。 (这是一个Linux示例)。

为了做一个正确的例子,首先我需要一些可以对CGI Web服务器进行非常简单的模拟的东西,最好是通过一个命令行。找到perldebug后,我发现Simple command line web server for running cgis. (perlmonks.org)适用于此测试。

在这里,我将在/tmp目录中工作; CGI脚本将为/tmp/test.pl(包括在下面)。请注意,IO::All服务器仅提供与CGI位于同一目录中的可执行文件,因此此处需要chmod +x test.pl。因此,要进行通常的CGI测试运行,我将目录更改为终端中的/tmp,并在那里运行单行Web服务器:

$ cd /tmp
$ perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'

webserver命令将在终端中阻塞,否则将在本地启动Web服务器(在127.0.0.1或localhost) - 之后,我可以转到Web浏览器,并请求此地址:

http://127.0.0.1:8080/test.pl

...我应该在网络浏览器中观察由print加载并显示的test.pl


现在,要使用RemotePort调试此脚本,首先我们需要网络上的侦听器,我们将通过它与Perl调试器进行交互;我们可以使用命令行工具netcatnc,在此处查看:IO::All - A Tiny Web Server)。因此,首先在一个终端中运行netcat侦听器 - 它将阻塞并等待端口7234上的连接(这将是我们的调试端口):

$ nc -l 7234

然后,当perl被调用时(即使在CGI模式下,通过服务器),我们希望RemotePorttest.pl启动调试模式。在Linux中,这可以使用以下“shebang wrapper”脚本完成 - 这里也需要在/tmp中,必须可执行:

cd /tmp

cat > perldbgcall.sh <<'EOF'
#!/bin/bash
PERLDB_OPTS="RemotePort=localhost:7234" perl -d -e "do '$@'"
EOF

chmod +x perldbgcall.sh

这有点棘手 - 请参阅Perl如何remote debug?。但是,这里的诀窍似乎是 not 来分叉处理perl的{​​{1}}解释器 - 所以一旦我们点击它,我们就不会test.pl,但是相反,我们使用exec“明白地”调用perl,并基本上“来源”我们的test.pl脚本。(请参阅shell script - How can I use environment variables in my shebang? - Unix & Linux Stack Exchange)。

现在我们在do中有perldbgcall.sh - 我们可以更改/tmp文件,以便它在其shebang行(而不是通常的Perl解释器)上引用此可执行文件 - 这里修改test.pl

/tmp/test.pl

现在,#!./perldbgcall.sh # this is test.pl use 5.10.1; use warnings; use strict; my $b = '1'; my $a = sub { "hello $b there" }; $b = '2'; print "YEAH " . $a->() . " CMON\n"; $b = '3'; print "CMON " . &$a . " YEAH\n"; $DB::single=1; # BREAKPOINT $b = '4'; print "STEP " . &$a . " NOW\n"; $b = '5'; print "STEP " . &$a . " AGAIN\n"; 及其新的shebang处理程序test.pl都位于perldbgcall.sh;我们/tmp监听端口7234上的调试连接 - 所以我们最终可以打开另一个终端窗口,将目录更改为nc,然后运行一线网络服务器(将侦听端口上的Web连接) 8080)那里:

/tmp

完成此操作后,我们可以转到我们的网络浏览器,并请求相同的地址cd /tmp perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })' 。但是,现在当Web服务器尝试执行脚本时,它将通过http://127.0.0.1:8080/test.pl shebang执行此操作 - 这将在远程调试器模式下启动perldbgcall.sh。因此,脚本执行将暂停 - 因此Web浏览器将锁定,等待数据。我们现在可以切换到perl终端,我们应该看到熟悉的Perl调试器文本 - 但是,通过netcat输出:

nc

正如代码段所示,我们现在基本上使用$ nc -l 7234 Loading DB routines from perl5db.pl version 1.32 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(-e:1): do './test.pl' DB<1> r main::(./test.pl:29): $b = '4'; DB<1> 作为“终端” - 因此我们可以为“运行”键入nc(和Enter) - 脚本将运行断点声明(另请参阅How do I run a Perl script from within a Perl script?),再次停止之前(请注意,此时浏览器仍会锁定)。

所以,现在我们可以通过r终端逐步完成test.pl的其余部分:

nc

...但是,此时,浏览器还会锁定并等待数据。只有在我们使用.... main::(./test.pl:29): $b = '4'; DB<1> n main::(./test.pl:30): print "STEP " . &$a . " NOW\n"; DB<1> n main::(./test.pl:31): $b = '5'; DB<1> n main::(./test.pl:32): print "STEP " . &$a . " AGAIN\n"; DB<1> n Debugged program terminated. Use q to quit or R to restart, use o inhibit_exit to avoid stopping after program termination, h q, h R or h o to get additional info. DB<1> 退出调试器后:

q

...浏览器是否会停止锁定 - 最后显示 DB<1> q $ 输出:

test.pl

当然,即使不运行Web服务器也可以进行这种调试 - 但是,这里的巧妙之处在于我们根本不接触Web服务器;我们从Web浏览器“本机地”(对于CGI)触发执行 - 并且CGI脚本本身所需的唯一更改是shebang的更改(当然,shebang包装脚本的存在,作为可执行文件在同一个中)目录)。

嗯,希望这有助于某人 - 我肯定会喜欢偶然发现这一点,而不是自己写YEAH hello 2 there CMON CMON hello 3 there YEAH STEP hello 4 there NOW STEP hello 5 there AGAIN 干杯!

答案 3 :(得分:7)

在调试时是否使用错误处理程序?

die语句和其他致命的运行时和编译时错误 打印到STDERR,这很难找到,可能会被混淆 来自您网站的其他网页的消息。当你正在调试你的 脚本,这是一个好主意,让你的致命错误信息显示在你的 浏览器莫名其妙。

执行此操作的一种方法是致电

   use CGI::Carp qw(fatalsToBrowser);

位于脚本的顶部。 That call将在浏览器中安装$SIG{__DIE__}处理程序(请参阅perlvar)显示致命错误,必要时在前面添加有效标头。在我听说CGI::Carp之前我使用的另一个CGI调试技巧是 使用eval与脚本上的DATA__END__工具来捕获编译时错误:

   #!/usr/bin/perl
   eval join'', <DATA>;
   if ($@) { print "Content-type: text/plain:\n\nError in the script:\n$@\n; }
   __DATA__
   # ... actual CGI script starts here

这种更详细的技术比CGI::Carp略有优势,因为它会捕获更多的编译时错误。

更新:我从未使用它,但看起来像CGI::Debug,就像Mikael S 建议,也是一个非常有用和可配置的工具。

答案 4 :(得分:5)

对我来说,我使用log4perl。它非常实用且简单。

use Log::Log4perl qw(:easy);

Log::Log4perl->easy_init( { level   => $DEBUG, file    => ">>d:\\tokyo.log" } );

my $logger = Log::Log4perl::get_logger();

$logger->debug("your log message");

答案 5 :(得分:1)

可能还值得一提的是,Perl将始终告诉您从命令行执行Perl脚本时出现错误的行。 (例如,SSH会话)

如果一切都失败了,我通常会这样做。我将SSH到服务器并手动执行Perl脚本。例如:

% perl myscript.cgi 

如果出现问题,Perl会告诉您相关信息。此调试方法可以消除任何与文件权限相关的问题或Web浏览器或Web服务器问题。

答案 6 :(得分:1)

老实说,你可以在这篇文章上面做所有有趣的事情。 尽管如此,我发现最简单,最主动的解决方案就是“打印”。

在示例中: (普通代码)

`$somecommand`;

看看它是否正在做我真正想做的事情: (故障排除)

print "$somecommand";

答案 7 :(得分:0)

您可以使用以下命令

在终端中运行perl cgi-script
 $ perl filename.cgi

它解释代码并使用HTML代码提供结果。如果有的话,它将报告错误。