我有一个用Perl编写的CGI脚本,它自己生成HTTP错误页面。我通过ModPerl::Registry在mod_perl下运行它,使用以下Apache2配置:
Alias /perl "/var/www/perl"
<Directory "/var/www/perl">
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
Options Indexes FollowSymlinks +ExecCGI
AllowOverride None
Order allow,deny
Allow from all
</Directory>
一切都很好,除了一个小问题:当HTTP状态打印在报头不同于200(例如404),Apache追加一个默认的HTML错误文档到我自己生成的响应。
以以下简单的CGI脚本为例:#!/usr/bin/perl
use strict;
use warnings;
use CGI qw(:standard :escapeHTML -nosticky);
use CGI::Carp qw(fatalsToBrowser);
use Apache2::Const qw(:http :common);
our $cgi = CGI->new();
print $cgi->header(-type=>'text/html', -charset => 'utf-8',
-status=> '404 Not Found');
our $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
print <<"EOF";
<html>
<head>
<title>die_error_minimal$mod_perl_version
</head>
<body>
404 error
</body>
</html>
EOF
exit;
用上面提到的Apache配置运行它会得到
HTTP/1.1 404 Not Found
Date: Sun, 27 Nov 2011 13:17:59 GMT
Server: Apache/2.0.54 (Fedora)
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
<html>
<head>
<title>die_error_minimal mod_perl/2.0.1
</head>
<body>
404 error
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /perl/die_error_minimal.cgi was not found on this server.</p>
<hr>
<address>Apache/2.0.54 (Fedora) Server at localhost Port 80</address>
</body></html>
注意,用return Apache2::Const::OK;
或return Apache2::Const::DONE;
替换上面示例CGI脚本中的exit;
,如"如何在mod_perl中抑制默认apache错误文档?"关于SO的问题没有帮助——结果保持不变。
我应该在我的Apache配置中修复什么,或者我应该添加什么到我的CGI脚本来抑制由mod_perl/Apache生成的响应附加错误页面?
FAQ为我工作,在你的CGI完成后,头被发送,告诉apache的状态是好的,所以它不发送ErrorDocumenthttp://search.cpan.org/沙丘状积砂/mod_perl - 1.31/常见问题/mod_perl_faq.pod # So_how_do_I_use_mod_perl_in_conjunction_with_ErrorDocument % 3 f
#!/usr/bin/perl --
use strict; use warnings;
use CGI;
Main( @ARGV );
exit( 0 );
sub Main {
my404();
#~ my $r = CGI::Simple->new->_mod_perl_request;
my $r = CGI->new->r;
$r->status(200);
return;
}
sub my404 {
my $cgi = CGI->new;
print $cgi->header( -status => 404 );
print "<html><title>print404 says tough noogies</title>
<body><h1>tough noogies</h1></body></html>";
}
__END__
GET http://localhost/perl/print404
User-Agent: lwp-request/6.03 libwww-perl/6.03
404 Not Found
Connection: close
Date: Sun, 27 Nov 2011 20:55:39 GMT
Server: Apache/2.0.54 (Win32) mod_ssl/2.0.54 OpenSSL/0.9.7g PHP/4.3.11 mod_perl/2.0.1 Perl/v5.8.9
Content-Type: text/html; charset=ISO-8859-1
Client-Date: Sun, 27 Nov 2011 20:55:39 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
Client-Transfer-Encoding: chunked
Title: print404 says tough noogies
<html><title>print404 says tough noogies</title>
<body><h1>tough noogies</h1></body></html>
我的代码版本,但工作更稳定:
#!/usr/bin/perl
use CGI qw/:standard/ ;
my $Content_of_webpage = 'Oops. 404 error ...' ;
my $status_code = 404 ;
if( $ENV{MOD_PERL} ) { # mod_perl ON
my $r = CGI->new->r ;
$r->status($status_code) ;
$r->content_type("text/html; charset=UTF-8") ;
$r->rflush ; # send the headers out << it is the trick :)
$r->status(200) ;
}
else { # mod_perl OFF
my $cgi = CGI->new ;
print $cgi->header(
-type => "text/html",
-status => $status_code,
-charset => 'UTF-8'
);
}
print $Content_of_webpage ;
我似乎面临着同样的问题:我设置报头状态为400,以防出现错误,并返回JSON数组来描述实际错误。
当我这样做的时候:
print $main::cgi->header(@ret), $html;
与变量:@ret: {'-type' => 'application/json','-charset' => 'utf-8','-status' => '400 Bad Request'}
$html: '{"errors":{"short_name":["Missing!"]}}'
我将以这个结尾:
Status Code: 200 OK
Content-Type: application/json; charset=utf-8
Response: {"errors":{"short_name":["Missing!"]}<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.2.3 (CentOS) Server at localhost Port 80</address>
</body></html>
使用faquer描述的方法确实会抑制错误文档,但仍然返回状态200 OK,如Jakub Narębski所指出的。
但是!我找到了一个解决方案,其中$r是Apache2::RequestRec,使用这个:http://perl.apache.org/docs/2.0/user/coding/coding.html#Forcing_HTTP_Response_Headers_Out(否则你会使用$r->send_http_header(),我猜)
print $main::cgi->header(@ret), $html;
my $r = $main::cgi->r;
$r->rflush; # force sending headers (with headers set by CGI)
$r->status(200); # tell Apache that everything was ok, dont send error doc.
HTTP响应:
Status Code: 400 Bad Request
Content-Type: application/json; charset=utf-8
Response: {"errors":{"short_name":["Missing!"]}}
Apache配置:
PerlModule ModPerl::PerlRun
PerlModule CGI
PerlModule Apache::DBI
PerlRequire /var/www/html/startup.pl
PerlSendHeader On
. htaccess:
<Files *.cgi>
SetHandler perl-script
PerlHandler ModPerl::PerlRun
Options ExecCGI
</Files>