Perl:通过mojolicious的异步http代理

Perl:通过mojolicious的异步http代理,perl,asynchronous,http-proxy,mojolicious,Perl,Asynchronous,Http Proxy,Mojolicious,我制作了一个简单的http代理,它工作得很好,但速度不快,因为在函数handle_请求中,我使用 my $tx = $ua->start( Mojo::Transaction::HTTP->new(req=>$request) ); 要执行请求,它正在阻塞 我尝试使用如下回调: $ua->start( Mojo::Transaction::HTTP->new(req=>$request) )=>sub{ ... } 要使其成为非阻塞,然后,出现了一个

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

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\u 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 =~ /^GET\s+|POST\s+|HEAD\s+(.*)\r\n\r\n$/i) {
                $buffer{$client}{read_buffer} = '';
                &handle_request($client,$stream,$buffer);
            }

            elsif ($buffer =~ /^CONNECT\s+(.*)\r\n\r\n$/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;
希望得到一些建议

您有两个问题:

  • 当代码具有阻塞样式时,尝试调用
    $ua->start
    的非阻塞变量。函数
    处理请求
    必须将回调作为参数。 如果您有回调链,那么实现它的最佳方法是使用
    Mojo::IOLoop::Delay
  • 当您在sub
    handle\u request
    中以非阻塞方式创建变量$ua时,您的变量将被垃圾收集器销毁,因为首先执行sub
    handle\u request的exit
    并销毁$ua,因为它是局部变量,然后从$ua获取答案。因此,您会提前关闭
    连接
    。您需要将$ua实例保存到其他位置以防止此类错误
  • Upd
    我发现http/https代理的一个坏变体,它只能通过CONNECT方法工作,并且有错误,第一条http消息不完整

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

    Upd

    哦,《魔咒》的作者写了一篇关于https代理的文章

    非常感谢。我在哈希表中存储$ua,现在就可以了。对于第一个问题,我不知道该怎么办<代码>我的$ua=Mojo::UserAgent->new$缓冲区{$client}{ua}=$ua;my$tx=$buffer{$client}{ua}->start(Mojo::Transaction::HTTP->new(req=>$request)=>sub{my($ua,$tx)=@;$stream->write($tx->res->to_string);})