调试Perl CGI程序 | |
日期:2001年7月17日 | |
——(译者注:本文译自PerlMonth—www.perlmonth.com,作者很幽默,但是有些语言我也翻译不出精髓,如果你读得不通或者觉得翻译的与你所理解的有所不同,可以查看原文——http://www.perlmonth.com/columns/begin/begin.html?issue=11&print=1) 这个月我们来一起学习如何调试PerlCGI脚本。这里所有的技巧和方法都是简单明了的;大多数方法你可能在你编程的第一课里就已经学到了,我说的是你要经过正式的Perl编程培训。然而,这也可能正是你面临的问题:如果你是一位自学的Perl程序员的话,你可能并没有接受过正规的调试CGI程序方面的教育。 那么我们先从这里开始吧。 假如你刚写了一个庞大的Perl程序,一个1000的CGI的经典脚本,来得到订单,处理信用卡,统计存货并且计算卫星的轨道J。你把它上传到服务器上,打开你的浏览器调阅程序。你发现出现了下面的东东: 500 Internal Server Error The server encountered an internal error or misconfiguration and was unable to complete your request. Please contact the server administrator, webmaster@foo.com and inform them of the time the error occurred, and anything you might have done that may have caused the error. More information about this error may be available in the server error log. 唔,这是什么玩意儿? 这有一个对CGI程序员来说非常好的资料—— The Idiot’s Guide to Solving Perl CGI Problems(解决Perl CGI问题的傻瓜指南 ftp://ftp.epix.net/pub/languages/perl/doc/FAQs/cgi/idiots-guide.html)不要因为题目而感到不快,其实我们都是傻瓜——在某些时候。先让我们试试他们的建议,看看是什么出错了。 第一步:检查脚本是否是可执行的。 ·确定你上传到了一个合适的目录。很多的服务器限定CGI程序只能在你的home或public_html目录下的特定子目录下执行——像是cgi-bin或是cgi-local。有时要放在统一的CGI目录下,例如:/usr/local/apache/cgi-bin ·检查脚本的文件扩展名是否与服务器设置的相符。一些服务器需要Perl CGI脚本以.cgi为扩展名;一些要以.pl为扩展名;其它的服务器没有这样的要求。 ·如果是放在Unix主机上,要检查脚本是“可执行”的。脚本的文件权限必须设置为允许执行。在telnet登录时你可以这样完成: $ chmod 0755 myscript.cgi 或者可以使用FTP软件来改变你上传的脚本的可执行权限。 ·检查服务器上已经安装了运行脚本所需的所有东西。 最后还有另外一些的工作。当我使用一些新的服务器的时候我首先要上传两个测试文件(作为一个自由作家,我每周都会遇到一两个新服务器,有时候我甚至是在那个服务器上尝试运行Perl CGI的第一个人)。一般最简单的测试文件是这样写的: #! /usr/bin/perl –w use diagnostics; print ‘Content-type: text/html Hello,world.’; 这个脚本会让你知道Perl CGI已经运行,服务器也设置好了可以正确处理Perl CGI。 如果你想要进一步的测试,那么我还是建议你试试perldiver(http://www.scriptsolutions.com/programs/free/perldiver/)。这是一个非常有用的脚本,你把它上载到服务器上运行,会得到一个详细又容易理解的服务器报告——Perl解释器的位置,安装了什么模块等大量信息。(你应该在检查你的服务器之后立即把这个脚本删除,它提供的很多信息会给不道德的使用者进行攻击提供可乘之机。) 那么,通过这些步骤你还没有找到错误所在?下一步就是要检查你的脚本是否被干净的编译了。你应该完成重要的一步——在你所有的脚本以这样的方式开始; #!/usr/bin/perl –w user diagnostics; 第一行是给操作系统的一个标准信号:通知Perl解释器要把该文件的其余部分作为源码解释。但是附加的“-w”开关,打开编译时和运行时的警告。第二行会打开“pragma”(一个编译选项),所有的错误信息和警告信息都会详细地显示,包括令人痛苦的所有大量的细节解释。这些细节信息有时也可以通过命令行的调试来得到——那时你的输出多得让屏幕不断地上滚,你会被上百行的错误诊断信息烦恼的痛苦不堪。但是在CGI的世界里我们就提供这些东西,不管你爱不爱看。 你也可能想把第三行加入到你的代码中: use strict; 我对把这条推荐给所有人表示犹豫,因为我并不为这条标准所左右。(我想说的是你应该去尝试,直到你知道了一种观点的想要做的是什么,然后再按你自己的想法来决定。)通常来说,“use strict”编译选项使Perl更像其他的需要预先声明变量的语言。(当然这个选项不只做这些用途) 现在你把这几行加入到你的脚本中,并按命令行方式运行你的代码: $ perl –c myscript.cgi 也许现在你可以看到一些语法错误或是其他的问题。(我在这里经常遇到的是缺少一个可选的包,如:Mail::Mailer)。你可以得到更多的出错信息,这比在浏览器中蹦出的可怕的500错误提示要好多了。 但是如果你没有权限,或根本不能在命令行方式下运行Perl解释器该怎么办呢?(这种可能性微乎其微,Perl在大多数操作系统中是可用的,尽管版本之间的差别可能会是很微小的也可能是很巨大的。但是也许你是在Windows系统中进行开发工作,却又不想把Perl安装到微软的系统上,或者你想在一台借来的计算机上快速调试一段脚本,你又不想为了几分钟的工作就安装一大堆Perl系统)。 其实我们只需要一个FTP客户端和一个浏览器就能完成所有的调试工作。首先我们要对你的脚本作一些改变: use CGI qw(:standard); use CGI::Carp qw(fatalsToBrowser); BEGIN{ Print CGI::header(); Open (STDERR, ‘>myscript.log’); } 上面的这几行,或者是其他的与其相似的东东,被放在我写的所有的CGI脚本中。第一行里引用的是标准CGI.pm包。的确,这是一个大包,大的有点像在港口外航行的航空母舰。但是它节省了你很多的时间,所以即使大一点也是值得的。除非你的Web服务器是运行在486机器上的,否则不要太在意载入这个包所多花的几微秒时间。如果你的脚本所在的网站的点击率像Yahoo!那样的大网站一样多,你也仍然可以使用CGI.pm包或其它的模块,但是你也必须学习如何使用mod_perl(这已经超出了本文所讨论的范围。不过,使用CGI.pm对你来说是一个非常好的选择,相信我,因为我是一个专家) 第二行引用的是另一个包叫做“CGI::Carp”,这是一个错误处理包它代替并扩展了我们经常看到的出错信息。之所以要把它从CGI一族中提取出来是因为我们想更精细的格式出错信息,而且还想通过内部程序fatalsToBrowser提供一个错误捕获机制。当发生严重错误的时候这个fatalsToBrowser子程序会获得脚本的控制权,并在浏览器上显示这个错误的具体内容(代替了500错误)。 第三行定义了一个BEGIN块。根据Perl的语法,你可以在程序中的任何部位插入代码块(包含文件或是模块)。当程序被解析的时候,这些块只被执行一次(所以它们是“编译阶段代码”)。向我所演示的一样,这些代码会通过STDERR把进一步的输出重定向到一个log文件中去。这在CGI环境中是比较方便的,因为大多数的错误不是被抑制了,就是被写到一个集中的站点错误日志中,这个日志会非常大并且可能不易被你阅读。 这里还有一样东西被特意放到了BEGIN块中来挽救你的不幸。那就是“print CGI::header”语句。在输出任何错误之前,强制返回给浏览器一个合适的HTTP头,通常的header的形式是这样的: Content-type: text/html (包括那个空行)。如果你的脚本已经有了一个头,那么你会在你的文档开始处看到多出了一个以文本显示的“header”。不用管它,当你结束调试的时候,你可以从BEGIN块中删除掉print语句,继续使用你原来的头。 当然,如果你的脚本使用了Content-type以外的header(比如说:cookie或是重定向),那么你的header会被BEGIN块中的header忽略。当我们证明所有的bug都被清除之后,就可以移除BEGIN块中的header。 现在,脚本中添加了这些行之后,你就可以很好地捕获并处理错误,并防止“500”之类的错误提示了。 (译自 PerlMonth / Jeff Boes) |