我需要一个Perl CGI脚本来获取URL,然后将获取的结果 - 状态,标题和内容 - 返回到CGI环境,以便Web服务器将“代理”URL返回给用户浏览器好像他们直接访问了网址。
我在Ubuntu 14.04主机上的Apache Web服务器上运行来自cgi-bin的脚本,但这个问题应该独立于服务器平台 - 任何可以运行Perl CGI脚本的东西应该能够做到。
我尝试过使用LWP :: UserAgent :: request()并且我已经非常接近了。它返回一个HTTP :: Response对象,其中包含状态代码,标题和内容,甚至还有一个“as_string”方法,将其转换为人类可读的形式。从CGI的角度来看问题是“as string”将状态代码转换为“HTTP / 1.1 200 OK”而不是“Status:200 OK”,因此Apache服务器不会将输出识别为有效的CGI响应。 / p>
我可以通过在HTTP :: Response中使用其他方法来解决这个问题来分解各个部分,但似乎没有公开的方法来获取封装的HTTP :: Headers对象以调用其as_string方法;相反,我必须入侵Perl祝福的对象哈希并直接抽出私人“_headers”成员。对我来说,这似乎有点邪恶,那么还有更好的方法吗?
这里有一些代码来说明上述内容。如果将它放在cgi-bin目录中,则可以将其称为
http://localhost/cgi-bin/lwp-test?url=http://localhost/&http-response=1&show=1
如果需要,您可以使用其他网址进行测试。如果您设置http-response=0
(或完全删除参数),那么您将获得逐个工作的解决方案。如果设置show=0
(或删除它),脚本将返回代理请求。如果你有http-response = 0,Apache将返回代理页面,如果是1,则会出现500内部服务器错误。
#!/usr/bin/perl
use strict;
use warnings;
use CGI::Simple;
use HTTP::Request;
use HTTP::Response;
use LWP::UserAgent;
my $q = CGI::Simple->new();
my $ua = LWP::UserAgent->new();
my $req = HTTP::Request->new(GET => $q->param('url'));
my $res = $ua->request($req);
# print a text/plain header if called with "show=1" in the query string
# so proxied URL response is shown in browser, otherwise just output
# the proxied response as if it was ours.
if ($q->param('show')) {
print $q->header("text/plain");
print "\n";
}
if ($q->param('http-response')) {
# This prints the status as "HTTP/1.1 200 OK", not "Status: 200 OK".
print $res->as_string;
} else {
# This works correctly as a proxy, but using {_headers} to get at
# the private encapsulated HTTP:Response object seems a bit evil.
# There must be a better way!
print "Status: ", $res->status_line, "\n";
print $res->{_headers}->as_string;
print "\n";
print $res->content;
}
请记住,这个脚本纯粹是为了演示如何将HTTP::Response
对象转发到CGI环境而与我的实际应用程序没有任何相似之处。
答案 0 :(得分:3)
您可以使用$res->{_headers}
方法绕过$res->headers
处的响应对象的内部,该方法返回所使用的实际HTTP :: Headers实例。 HTTP :: Response从HTTP::Message继承。
它看起来像这样:
print "Status: ", $res->status_line, "\n";
print $res->headers->as_string;
看起来不那么邪恶,虽然它仍然不漂亮。
答案 1 :(得分:1)
正如simbabque所指出的,HTTP :: Response通过从HTTP :: Message继承而具有headers
方法。我们可以通过使用HTTP::Response->header
将其推入嵌入式HTTP :: Headers对象来整理状态代码的处理,然后使用headers_as_string
更清晰地打印出标题。这是最后的剧本: -
#!/usr/bin/perl
use strict;
use warnings;
use CGI::Simple;
use HTTP::Request;
use HTTP::Response;
use LWP::UserAgent;
my $q = CGI::Simple->new();
my $ua = LWP::UserAgent->new();
my $req = HTTP::Request->new(GET => $q->param('url'));
my $res = $ua->request($req);
# print a text/plain header if called with "show=1" in the query string
# so proxied URL response is shown in browser, otherwise just output
# the proxied response as if it was ours.
if ($q->param('show')) {
print $q->header("text/plain");
}
# $res->as_string returns the status in a "HTTP/1.1 200 OK" line rather than
# a "Status: 200 OK" header field so it can't be used for a CGI response.
# We therefore have a little more work to do...
# convert status from line to header field
$res->header("Status", $res->status_line);
# now print headers and content - don't forget a blank line between the two
print $res->headers_as_string, "\n", $res->content;