简体   繁体   English

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

[英]Better way to proxy an HTTP request using Perl HTTP::Response and LWP?

I need a Perl CGI script that fetches a URL and then returns the result of the fetch - the status, headers and content - unaltered to the CGI environment so that the "proxied" URL is returned by the web server to the user's browser as if they'd accessed the URL directly. 我需要一个Perl CGI脚本,该脚本将获取URL,然后将获取的结果(状态,标头和内容)保持不变,而不会更改到CGI环境,以便Web服务器将“代理” URL返回给用户的浏览器,就像他们直接访问了网址。

I'm running my script from cgi-bin in an Apache web server on an Ubuntu 14.04 host, but this question should be independent of server platform - anything that can run Perl CGI scripts should be able to do it. 我正在Ubuntu 14.04主机上的Apache Web服务器中的cgi-bin中运行脚本,但是此问题应独立于服务器平台-可以运行Perl CGI脚本的任何东西都应该能够做到。

I've tried using LWP::UserAgent::request() and I've got very close. 我已经尝试过使用LWP :: UserAgent :: request(),并且已经很接近了。 It returns an HTTP::Response object that contains the status code, headers and content, and even has an "as_string" method that turns it into a human-readable form. 它返回一个HTTP :: Response对象,该对象包含状态码,标头和内容,甚至还具有一个“ as_string”方法,该方法会将其转换为易于理解的形式。 The problem from a CGI perspective is that "as string" converts the status code to "HTTP/1.1 200 OK" rather than "Status: 200 OK", so the Apache server doesn't recognise the output as a valid CGI response. 从CGI角度来看,问题是“作为字符串”将状态代码转换为“ HTTP / 1.1 200 OK”,而不是“ Status:200 OK”,因此Apache服务器无法将输出识别为有效的CGI响应。

I can fix this by using other methods in HTTP::Response to split out the various parts, but there seems to be no public way of getting at the encapsulated HTTP::Headers object in order to call its as_string method; 我可以通过使用HTTP :: Response中的其他方法来拆分各个部分来解决此问题,但是似乎没有公开的方法来获取封装的HTTP :: Headers对象以调用其as_string方法; instead I have to hack into the Perl blessed object hash and yank out the private "_headers" member directly. 取而代之的是,我不得不侵入Perl祝福的对象哈希,并直接提取私有的“ _headers”成员。 To me this seems slightly evil, so is there a better way? 对我来说,这似乎有点邪恶,所以有更好的方法吗?

Here's some code to illustrate the above. 这里是一些说明上述内容的代码。 If you put it in your cgi-bin directory then you can call it as 如果将其放在cgi-bin目录中,则可以将其称为

http://localhost/cgi-bin/lwp-test?url=http://localhost/&http-response=1&show=1 HTTP://本地主机/的cgi-bin / LWP测试URL = HTTP://本地主机/&HTTP的响应= 1&显示= 1

You can use a different URL for testing if you want. 如果需要,可以使用其他URL进行测试。 If you set http-response=0 (or drop the param altogether) then you get the working piece-by-piece solution. 如果将http-response=0 (或完全删除该参数),则将得到工作中的逐个解决方案。 If you set show=0 (or drop it) then the proxied request is returned by the script. 如果设置show=0 (或删除它),则脚本将返回代理请求。 Apache will return the proxied page if you have http-response=0 and will choke with a 500 Internal Server Error if it's 1. 如果您具有http-response = 0,则Apache将返回代理页面,如果为1,则将显示500 Internal Server Error。

#!/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;
}

Please bear in mind that this script was written purely to demonstrate how to forward an HTTP::Response object to the CGI environment and bears no resemblance to my actual application. 请记住,该脚本的编写纯粹是为了演示如何将HTTP::Response对象转发到CGI环境,与我的实际应用程序没有任何相似之处。

You can go around the internals of the response object at $res->{_headers} by using the $res->headers method, that returns the actual HTTP::Headers instance that is used. 您可以使用$res->headers方法在$res->headers $res->{_headers}$res->{_headers}响应对象的内部,该方法返回实际使用的HTTP :: Headers实例。 HTTP::Response inherits that from HTTP::Message . HTTP :: Response继承自HTTP :: Message

It would then look like this: 然后看起来像这样:

print "Status: ", $res->status_line, "\n";
print $res->headers->as_string;

That looks less evil, though it's still not pretty. 尽管看起来还不是很漂亮,但看起来似乎不太邪恶。

As simbabque pointed out, HTTP::Response has a headers method through inheritance from HTTP::Message. 正如simbabque所指出的那样,HTTP :: Response通过从HTTP :: Message继承而具有headers方法。 We can tidy up the handling of the status code by using HTTP::Response->header to push it into the embedded HTTP::Headers object, then use headers_as_string to print out the headers more cleanly. 我们可以使用HTTP::Response->header将状态代码推送到嵌入式HTTP :: Headers对象中,从而整理状态代码的处理,然后使用headers_as_string更清晰地打印出标题。 Here's the final script:- 这是最终的脚本:

#!/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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM