Perl:一个通过mojolicus的异步http代理



我做了一个简单的http代理,它工作得很好,但速度不快,因为在函数handle_request中,我使用

my $tx = $ua->start( Mojo::Transaction::HTTP->new(req=>$request) );

要执行请求,它正在阻止。

我试着使用一个回调,比如:

$ua->start( Mojo::Transaction::HTTP->new(req=>$request) )=>sub{ ... }

让它成为非阻塞的,然后,得到了一个错误:

'error' => { 'message' => 'Premature connection close'}

我想这是因为函数handle_request立即返回,它不等待回调完成。如果我使用信号量来等待回调,那就意味着它又被阻塞了。

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Mojo::IOLoop::Server;
use Mojo::UserAgent;
use Mojo::Message::Response;
use Mojo::Message::Request;
use Mojo::Transaction::HTTP;
use Data::Dumper;
binmode STDOUT, ":encoding(UTF-8)";
my %buffer;
Mojo::IOLoop->server( {port => 3128} => sub {
    my ($loop, $stream, $client) = @_;
    $stream->on(
        read => sub {
            my ($stream, $chunk) = @_;
            my $buffer = $buffer{$client}{read_buffer} .= $chunk;
            if ($buffer =~ /^GETs+|POSTs+|HEADs+(.*)rnrn$/i) {
                $buffer{$client}{read_buffer} = '';
                &handle_request($client,$stream,$buffer);
            }
            elsif ($buffer =~ /^CONNECTs+(.*)rnrn$/i) {
                $buffer{$client}{read_buffer} = '';
                &handle_connect($stream,$buffer);
            }
            elsif($buffer{$client}{connection})
            {
                $buffer{$client}{read_buffer} = '';
                Mojo::IOLoop->stream($buffer{$client}{connection})->write($chunk);
            }
            if(length($buffer)>= 20 *1024 * 1024) {
                delete $buffer{$client};
                Mojo::IOLoop->remove($client);
                return;
            }
        });
});
sub handle_request{
    my($client,$stream,$chunk) = @_;
    my $request = Mojo::Message::Request->new;
    $request = $request->parse($chunk);
    my $ua = Mojo::UserAgent->new;
    my $tx = $ua->start( Mojo::Transaction::HTTP->new(req=>$request) );
    $stream->write( $tx->res->to_string );
}
sub handle_connect{
    my ($stream, $chunk) = @_;
    my $request = Mojo::Message::Request->new;
    my $ua = Mojo::UserAgent->new;
    $request = $request->parse($chunk);
    print Dumper($request);
}
Mojo::IOLoop->start;

希望能得到一些建议。

您有两个问题:

  1. 当代码具有阻塞样式时,可以尝试调用$ua->start的非阻塞变体。函数handle_request必须具有回调作为参数。如果您有回调链,那么实现它的最佳方法是使用Mojo::IOLoop::Delay
  2. 当您在子handle_request中以非阻塞样式创建变量$ua时,您的变量将被垃圾收集器销毁,因为首先执行子handle_request的出口,$ua将被销毁,因为它是局部变量,然后从$ua获得答案。所以你得到了Premature connection close。您需要将$ua的实例保存到其他地方以防止出现此类错误

上升
我写了一个糟糕的http/https代理变体,它只能通过CONNECT方法工作,并且有第一个http消息不完整的错误。

上升
我添加了另一个http/https代理的例子,它正确地读取了第一条http消息,并且不仅通过CONNECT方法工作。

上升
哦,Mojo的作者写了https代理的例子

最新更新