使用Perl HTTP :: Response和LWP代理HTTP请求的更好方法是什么?

时间:2016-01-07 14:03:12

标签: perl http-headers cgi lwp lwp-useragent

我需要一个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环境而与我的实际应用程序没有任何相似之处。

2 个答案:

答案 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;