#!/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
我想知道为什么没有人提到PERLDB_OPTS选项RemotePort;尽管无可否认,Web上没有太多可用的示例(RemotePort甚至没有在perldebug中提到)--而且我提出这个示例有点问题,但它就在这里(它是一个Linux示例)。 为了做一个合适的示例,首先我需要一个可以对CGI Web服务器进行非常简单的模拟的东西,最好是通过一个命令行。在找到Simple command line web server for running cgis. (perlmonks.org)之后,我发现IO::All-A Tiny Web Server适用于此测试。 在这里,我将在/tmp目录中工作; CGI脚本将是/tmp/test.pl(包含在下面)。注意IO::All服务器只提供与CGI相同目录下的可执行文件,因此这里需要chmod +x test.pl。因此,为了进行通常的CGI测试运行,我将终端中的目录更改为/tmp,并在那里运行一行程序web服务器:
The webserver command will block in the terminal, and will otherwise start the web server locally (on 127.0.0.1 or localhost ) - afterwards, I can go to a web browser, and request this address:
$ 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>
....
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的(完整)输出:
YEAH hello 2 there CMON
CMON hello 3 there YEAH
STEP hello 4 there NOW
STEP hello 5 there AGAIN
8条答案
按热度按时间46scxncf1#
这个答案旨在作为解决Perl CGI脚本问题的通用框架,最初在Perlmonks上以Troubleshooting Perl CGI Scripts的形式出现。它不是您可能遇到的每个问题的完整指南,也不是关于bug压制的教程。它只是我调试CGI脚本二十年经验的总结(加!)年。这个页面似乎有许多不同的家园,我似乎忘记了它的存在,所以我把它添加到StackOverflow。你可以发送任何意见或建议给我在bdfoy@cpan.org。它也是社区维基,但是不要太疯狂。:)
您是否使用Perl的内置特性来帮助您查找问题?
打开警告功能,让Perl警告您代码中有问题的部分。您可以在命令行中使用
-w
开关,这样您就不必更改任何代码或向每个文件添加杂注:但是,您应该强迫自己总是通过向所有文件添加
warnings
杂注来清除有问题的代码:如果您需要除简短警告消息之外的更多信息,请使用
diagnostics
杂注获取更多信息,或查看perldiag文档:是否先输出了有效的CGI头?
服务器希望CGI脚本的第一个输出是CGI标头。通常,它可能简单到
print "Content-type: text/plain\n\n";
或CGI.pm及其派生项print header()
。某些服务器对在标准输出(STDOUT
)之前显示错误输出(STDERR
)很敏感。尝试向浏览器发送错误
添加此行
添加到脚本中。这还会向浏览器窗口发送编译错误。请确保在移动到生产环境之前删除此错误,因为额外的信息可能会带来安全风险。
错误日志显示了什么内容?
服务器保存错误日志(或者至少应该保存)。服务器和脚本的错误输出应该显示在那里。找到错误日志,看看它说了什么。日志文件没有标准的位置。在服务器配置中查找它们的位置,或者询问服务器管理员。你也可以使用CGI::Carp之类的工具来保存你自己的日志文件。
脚本的权限是什么?
如果您看到“Permission denied”或“Method not implemented”之类的错误,这可能意味着您的脚本无法被Web服务器用户读取和执行。在Unix版本中,建议将模式更改为755:
chmod 755 filename
。切勿将模式设置为777!您使用的是
use strict
吗?请记住,Perl在你第一次使用变量时会自动创建变量。这是一个特性,但有时如果你输入错误的变量名会导致错误。pragma
use strict
会帮助你发现这类错误。在你习惯之前,这会很烦人,但一段时间后你的编程会有很大的改进,你可以自由地犯不同的错误。脚本是否编译?
您可以使用
-c
开关检查编译错误。集中注意报告的第一个错误。冲洗,重复。如果您遇到非常奇怪的错误,请检查以确保您的脚本具有正确的行尾。如果您以二进制模式FTP,从CVS checkout ,或其他不处理行尾转换的操作,网络服务器可能会把你的脚本看作一个大行。2以ASCII模式传输Perl脚本。脚本是否抱怨不安全的依赖项?
如果您的脚本抱怨不安全的依赖关系,您可能使用了
-T
开关来打开污点模式,这是一件好事,因为它可以让你通过未经检查的数据到 shell 。如果它抱怨,它正在做它的工作,以帮助我们编写更安全的脚本。任何数据来源于外部的程序(即环境)被认为是污染的。环境变量如PATH
和LD_LIBRARY_PATH
特别麻烦。你必须将它们设置为一个安全的值或完全取消设置。正如我建议的那样。无论如何,你应该使用绝对路径。如果污点检查抱怨其他的东西,确保你没有污染数据。详细信息请参见perlsec手册页。从命令行运行时会发生什么?
当从命令行运行时,脚本是否输出您期望的内容?是否首先输出标题,然后是空行?请记住,如果您在终端上,
STDERR
可能会与STDOUT
合并(例如交互式会话),并且由于缓冲可能会以混乱的顺序出现。通过将$|
设置为true值来打开Perl的自动刷新特性。通常你会在CGI程序中看到$|++;
。一旦设置,每次打印和写入都会立即输出,而不是被缓冲。你必须为每个文件句柄设置这个。使用select
来更改默认的文件句柄,如下所示:无论哪种方式,输出的第一件事应该是CGI头,后面跟着一个空行。
在类似CGI的环境中从命令行运行它会发生什么?
Web服务器环境通常比命令行环境更受限制,并且具有关于请求的额外信息。如果脚本从命令行运行正常,则可以尝试模拟Web服务器环境。如果出现问题,则存在环境问题。
取消设置或删除这些变量
PATH
ORACLE_*
变量设置这些变量
REQUEST_METHOD
(根据需要设置为GET
、HEAD
或POST
)SERVER_PORT
(通常设置为80)REMOTE_USER
(如果您正在执行受保护的访问操作)CGI.pm
的最新版本(〉2.75)需要-debug
标志来获得旧的(有用的)行为,因此您可能必须将其添加到CGI.pm
导入中。您使用的是
die()
还是warn
?这些函数打印到
STDERR
,除非你重新定义了它们。它们也不输出CGI头。你可以用像CGI::Carp这样的包得到同样的功能清除浏览器缓存后会发生什么?
如果你认为你的脚本在做正确的事情,并且当你手动执行请求时你得到了正确的输出,那么浏览器可能是罪魁祸首。在测试时清除该高速缓存并将缓存大小设置为零。记住,有些浏览器真的很愚蠢,即使你告诉它这样做,它也不会真正重新加载新内容。这在URL路径相同的情况下尤其普遍。但是内容改变(例如动态图像)。
脚本是否在您认为的位置?
脚本的文件系统路径不一定与脚本的URL路径直接相关。请确保目录正确,即使必须编写简短的测试脚本来进行测试也是如此。此外,是否确实修改了正确的文件?如果更改没有任何效果,则可能是修改了其他文件,或者将文件上载到了错误的位置。(顺便说一句,这是我最经常引起这种麻烦的原因;)
您使用的是
CGI.pm
还是它的衍生产品?如果您的问题与解析CGI输入有关,并且您没有使用
CGI.pm
、CGI::Request
、CGI::Simple
或CGI::Lite
等经过广泛测试的模块,请使用这些模块并继续使用。CGI.pm
具有cgi-lib.pl
兼容模式,可以帮助您解决由于旧CGI解析器实现而导致的输入问题。是否使用绝对路径?
如果你正在运行带有
system
、反勾号或其他IPC工具的外部命令,你应该使用外部程序的绝对路径。你不仅知道你正在运行什么,而且还可以避免一些安全问题。如果你正在打开文件进行阅读或写,使用绝对路径。CGI脚本可能与您对当前目录有不同的想法。或者,您可以执行显式chdir()
来将您置于正确的位置。是否检查了返回值?
大多数Perl函数会告诉你它们是否工作,并在失败时设置
$!
。你检查了返回值并检查了$!
的错误消息吗?如果你使用eval
,你检查了$@
吗?您使用的是哪个版本的Perl?
Perl的最新稳定版本是5.28(或不是,取决于最后一次编辑的时间)。您使用的是旧版本吗?不同版本的Perl可能有不同的警告。
您正在使用哪个Web服务器?
不同的服务器在相同的情况下可能会有不同的行为。相同的服务器产品在不同的配置下可能会有不同的行为。请在任何帮助请求中尽可能多地提供此信息。
是否查看了服务器文档?
认真的CGI程序员应该尽可能多地了解服务器--不仅包括服务器的功能和行为,还包括本地配置。如果您使用的是商业产品,则可能无法获得服务器的文档。否则,服务器上应该有文档。如果没有,请在Web上查找。
您搜索过
comp.infosystems.www.authoring.cgi
的归档文件吗?很可能有人以前遇到过您的问题,并且有人(可能是我)在此新闻组中回答过您的问题。虽然此新闻组已过鼎盛时期,但从过去收集的智慧有时是有用的。
是否可以使用简短的测试脚本重现该问题?
在大型系统中,由于发生的事情太多,要追踪一个bug可能会很困难。尝试用尽可能短的脚本重现问题行为。知道问题是修复的主要部分。这当然会很耗时,但你还没有找到问题,而且你已经没有选择了。:)
你决定去看电影了吗?
说真的。有时候我们会太过专注于问题,以至于产生了“感知狭窄”(隧道视野)。休息一下,喝杯咖啡,或者在《杜克》、《雷神之锤》、《末日》、《光晕》、《COD》中干掉一些坏人,可能会给予你重新解决问题所需的新鲜视角。
你说出问题了吗?
说真的。有时候大声解释问题会让我们找到自己的答案。和企鹅(毛绒玩具)说话,因为你的同事没有在听。如果你对这个调试工具感兴趣(如果你现在还没有发现问题,我推荐你使用它),你可能也想读一下The Psychology of Computer Programming。
3yhwsihp2#
我认为CGI::Debug也值得一提。
nhhxz33t3#
在调试时是否使用错误处理程序?
die
语句和其他致命的运行时和编译时错误会打印到STDERR
,这些错误可能很难找到,并且可能会与站点中其他网页的消息混在一起。在调试脚本时,最好以某种方式在浏览器中显示致命错误消息。一种方法是调用
在脚本的顶部。该调用将安装一个
$SIG{__DIE__}
处理程序(参见perlvar),在浏览器中显示致命错误,如果需要的话,在它前面加上一个有效的头。在我听说CGI::Carp
之前,我使用的另一个CGI调试技巧是在脚本上使用eval
和DATA
和__END__
工具来捕获编译时错误:这种更详细的技术比
CGI::Carp
稍有优势,因为它将捕获更多的编译时错误。**更新:**我从来没有使用过它,但正如Mikael S建议的那样,
CGI::Debug
似乎也是一个非常有用的、可配置的工具。kqqjbcuj4#
我想知道为什么没有人提到
PERLDB_OPTS
选项RemotePort
;尽管无可否认,Web上没有太多可用的示例(RemotePort
甚至没有在perldebug中提到)--而且我提出这个示例有点问题,但它就在这里(它是一个Linux示例)。为了做一个合适的示例,首先我需要一个可以对CGI Web服务器进行非常简单的模拟的东西,最好是通过一个命令行。在找到Simple command line web server for running cgis. (perlmonks.org)之后,我发现IO::All-A Tiny Web Server适用于此测试。
在这里,我将在
/tmp
目录中工作; CGI脚本将是/tmp/test.pl
(包含在下面)。注意IO::All
服务器只提供与CGI相同目录下的可执行文件,因此这里需要chmod +x test.pl
。因此,为了进行通常的CGI测试运行,我将终端中的目录更改为/tmp
,并在那里运行一行程序web服务器:The webserver command will block in the terminal, and will otherwise start the web server locally (on 127.0.0.1 or
localhost
) - afterwards, I can go to a web browser, and request this address:......我应该观察到
test.pl
制作的print
正在Web浏览器中加载-并显示。现在,要用
RemotePort
调试这个脚本,首先我们需要在网络上有一个 * 侦听器 *,通过它我们将与Perl调试器交互;我们可以使用命令行工具netcat
(nc
,见此处:因此,首先在一个终端中运行netcat
侦听器-它将阻塞并等待端口7234(将是我们的调试端口)上的连接:然后,当
test.pl
被调用时(即使是在CGI模式下,通过服务器),我们希望perl
在调试模式下以RemotePort
启动。在Linux中,这可以使用下面的"shebang wrapper"脚本来完成-这里也需要在/tmp
中,并且 * 必须 * 是可执行的:这是一件棘手的事情--参见shell script - How can I use environment variables in my shebang? - Unix & Linux Stack Exchange。但是,这里的技巧似乎是 * 不 * 派生处理
test.pl
的perl
解释器--所以一旦我们遇到它,我们就不使用exec
,而是"简单地"调用perl
,并且基本上使用do
来"源"我们的test.pl
脚本(参见How do I run a Perl script from within a Perl script?)。现在我们在
/tmp
中有了perldbgcall.sh
-我们可以修改test.pl
文件,使其在shebang行引用此可执行文件(而不是通常的Perl解释器)-下面是修改后的/tmp/test.pl
:现在,
test.pl
和它的新shebang处理程序perldbgcall.sh
都在/tmp
中;并且我们有nc
监听端口7234上的调试连接-所以我们最终可以打开另一个终端窗口,将目录更改为/tmp
,并在那里运行一行程序webserver(它将监听端口8080上的web连接):完成后,我们可以转到Web浏览器,并请求相同的地址
http://127.0.0.1:8080/test.pl
。但是,现在当Web服务器尝试执行脚本时,它将通过perldbgcall.sh
shebang执行,这将以远程调试器模式启动perl
。因此,脚本执行将暂停,Web浏览器将锁定。我们现在可以切换到netcat
终端,应该会看到熟悉的Perl调试器文本--但是,通过nc
输出:如代码片段所示,我们现在基本上使用
nc
作为"终端"-因此我们可以键入r
(和Enter)表示"运行"-脚本将运行断点语句(另请参见In perl, what is the difference between $DB::single = 1 and 2?),然后再次停止(注意,此时浏览器仍将锁定)。那么,现在我们可以通过
nc
终端逐步执行test.pl
的其余部分:...但是,也是在此时,浏览器锁定并等待数据。只有在我们使用
q
退出调试器之后:...浏览器是否停止锁定-并最终显示
test.pl
的(完整)输出:当然,这种调试甚至可以在不运行web服务器的情况下完成--然而,这里的巧妙之处在于,我们根本不接触web服务器;我们从网络浏览器"本地"触发执行(对于CGI)-CGI脚本本身唯一需要的改变是shebang的改变(当然,shebang Package 器脚本的存在,作为同一目录中的可执行文件)。
好吧,希望这对某些人有帮助-我当然很想偶然发现这一点,而不是自己写
:)
干杯!
tktrz96b5#
对我来说,我使用log4perl,它非常有用和容易。
sgtfey8w6#
老实说,你可以做这篇文章上面所有有趣的事情。尽管如此,我找到的最简单、最积极主动的解决方案就是“打印出来”。
例如:(正常代码)
看看它是否在做我真正想让它做的事情:(故障排除)
zfciruhq7#
可能还值得一提的是,当您从命令行执行Perl脚本时,Perl总是会告诉您错误发生在哪一行(例如SSH会话)。
如果其他方法都失败了,我通常会这样做。我将SSH连接到服务器,然后手动执行Perl脚本。例如:
如果有问题,Perl会告诉你,这种调试方法可以解决任何文件权限相关的问题,或者Web浏览器或Web服务器的问题。
mcdcgff08#
您可以使用以下命令在终端中运行perl cgi-script
它解释代码并以HTML代码提供结果。如果有错误,它会报告。