【发布时间】:2016-04-11 23:00:33
【问题描述】:
我需要一个 Perl CGI 脚本来获取 URL,然后返回获取的结果 - 状态、标题和内容 - 不改变 CGI 环境,以便 Web 服务器将“代理” URL 返回到用户的就像他们直接访问了 URL 一样。
我在 Ubuntu 14.04 主机上的 Apache Web 服务器中从 cgi-bin 运行我的脚本,但这个问题应该独立于服务器平台 - 任何可以运行 Perl CGI 脚本的东西都应该能够做到。
我尝试过使用 LWP::UserAgent::request() 并且非常接近。它返回一个包含状态代码、标头和内容的 HTTP::Response 对象,甚至还有一个“as_string”方法,可以将其转换为人类可读的形式。从 CGI 的角度来看,问题是“作为字符串”将状态代码转换为“HTTP/1.1 200 OK”而不是“状态:200 OK”,因此 Apache 服务器无法将输出识别为有效的 CGI 响应。
我可以通过使用 HTTP::Response 中的其他方法来拆分各个部分来解决此问题,但似乎没有公开的方法可以获取封装的 HTTP::Headers 对象以调用其 as_string 方法;相反,我必须侵入 Perl 祝福对象哈希并直接拉出私有“_headers”成员。对我来说这似乎有点邪恶,那么有更好的方法吗?
这里有一些代码来说明上述内容。如果你把它放在你的 cgi-bin 目录中,那么你可以把它称为
http://localhost/cgi-bin/lwp-test?url=http://localhost/&http-response=1&show=1
如果需要,您可以使用不同的 URL 进行测试。如果您设置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 环境而编写的,与我的实际应用程序没有任何相似之处。
【问题讨论】:
-
您可以编辑并使实际的任务更明显吗?我觉得它隐藏在文本中太多了。问题是什么?
-
我已经编辑了这个问题。这是否使它更清楚?基本上它分为 4 个部分:(1)这是我想要做的(代理 URL 获取); (2) 我是这样做的(使用 LWP); (3)这是我的解决方案的问题(依赖于HTTP::Response内部结构的知识); (4) 有没有更好的方法?
-
在不同的想法上,我发现this answer 了解如何制作代理。它把我带到check in HTTP::Daemon,它有一个方法send_response,它接受一个HTTP::Response 对象。可能会有一些转换可以满足您的需要。我认为值得一读的代码。
-
我快速浏览了一下 code 和
send_response并没有做任何与我的解决方案有明显不同的事情:它使用$res->code来获取状态代码编号(我使用status_line获取代码+消息);它使用$res->header(field,value)处理标题字段,然后使用$res->headers_as_string对它们进行字符串化;它使用$res->content来获取内容。看起来我的公司很好!
标签: perl http-headers cgi lwp lwp-useragent