Why do I need to explicitly output the HTTP header

2019-06-19 04:24发布

问题:

I am trying to set up apache instead of IIS because IIS needlessly crashes all the time, and it would be nice to be able to have my own checkout of the source instead of all of us editing a common checkout.

In IIS we must do something like this at the beginning of each file:

use CGI;
my $input = new CGI();
print "HTTP/1.0 200 OK";
print $input->header();

whereas with apache we must leave off the 200 OK line. The following works with both:

use CGI;
my $input = new CGI();
print $input->header('text/html','200 OK');

Can anyone explain why? And I was under the impression that the CGI module was supposed to figure out these kind of details automatically...

Thanks!

Update: brian is right, nph fixes the problem for IIS, but it is still broken for Apache. I don't think it's worth it to have conditionals all over the code so I will just stick with the last method, which works with and without nph.

回答1:

HTTP and CGI are different things. The Perl CGI module calls what it does an "HTTP header", but it's really just a CGI header for the server to fix up before it goes back to the client. They look a lot alike which is why people get confused and why the CGI.pm docs don't help by calling them the wrong thing.

Apache fixes up the CGI headers to make them into HTTP headers, including adding the HTTP status line and anything else it might need.

If you webserver isn't fixing up the header for you, it's probably expecting a "no-parsed header" where you take responsibility for the entire header. To do that in CGI.pm, you have to add the -nph option to your call to header, and you have to make the complete header yourself, including headers such as Expires and Last-Modified. See the docs under Creating a Standard HTTP Header. You can turn on NPH in three ways:

use CGI qw(-nph)

CGI::nph(1)

print header( -nph => 1, ...)

Are you using an older version of IIS? CGI.pm used to turn on the NPH feature for you automatically for IIS, but now that line is commented out in the source in CGI.pm:

# This no longer seems to be necessary
# Turn on NPH scripts by default when running under IIS server!
# $NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/;


回答2:

I'm still experiencing this problem with ActivePerl 5.14 running under IIS 7 via ISAPI. The ActivePerl 5.10 FAQ claims the problem is fixed (the 5.14 FAQ doesn't even address the issue), but it doesn't appear to be and setting the registry key they suggest using has no effect in this environment.

Using $ENV{PerlXS} eq 'PerlIS' to detect ISAPI and turn on the NPH key per the aforementioned FAQ seems to work. I hacked my CGI.pm to add the final two lines below under the old IIS handler:

# This no longer seems to be necessary
# Turn on NPH scripts by default when running under IIS server!
# $NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/;
# Turn on NPH scripts by default when running under IIS server via ISAPI!
$NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{PERLXS} eq 'PerlIS';


回答3:

I had similar problem with perl (it was a DOS/Unix/Mac newline thing !)

binmode(STDOUT);
my $CRLF = "\r\n"; # "\015\012"; # ^M: \x0D  ^L: \x0A
print "HTTP/1.0 200 OK",$CRLF if ($0 =~ m/nph-/o);
print "Content-Type: text/plain".$CRLF;
print $CRLF; print "OK !\n";