6

在 Perl 中从另一个 HTTP 资源流式传输的最简单方法是什么(无需打开 shell 来 curl 并从标准输入中读取)?我在这里假设我正在读取的 HTTP 资源是一个潜在的无限流(或者只是非常非常长)

4

5 回答 5

9

好的旧 LWP 允许您将结果作为流处理。

例如,这是对 yourFunc 的回调,读取/传递 byte_count 字节到对 yourFunc 的每次调用(如果您不关心每次调用的数据有多大,并且只想尽快处理流,则可以删除该参数):

use LWP;
...
$browser = LWP::UserAgent->new();
$response = $browser->get($url, 
                          ':content_cb' => \&yourFunc, 
                          ':read_size_hint' => byte_count,);
...
sub yourFunc {
   my($data, $response) = @_;
   # do your magic with $data
   # $respose will be a response object created once/if get() returns
}
于 2009-10-14T18:19:56.383 回答
6

HTTP::Literequest方法允许您指定回调。

$data_callback参数(如果使用)是一种在接收数据时过滤数据或处理大量传输的方法。它必须是函数引用,并且将被传递:对发出回调的 http 请求实例的引用、对将要添加到主体的当前数据块的引用以及$cbargs参数(可以是任何东西) . 它必须返回对要添加到文档正文的数据的引用,或者返回 undef。

但是,查看源代码,似乎存在一个错误sub request,它似乎忽略了传递的回调。使用起来似乎更安全set_callback

#!/usr/bin/perl

use strict;
use warnings;

use HTTP::Lite;

my $http = HTTP::Lite->new;
$http->set_callback(\&process_http_stream);
$http->http11_mode(1);

$http->request('http://www.example.com/');

sub process_http_stream {
    my ($self, $phase, $dataref, $cbargs) = @_;
    warn $phase, "\n";
    return;
}

输出:

C:\Temp> ht
连接
内容长度
完成标题
内容
内容完成
数据
完毕

看起来传递给该request方法的回调被不同地对待:

#!/usr/bin/perl

use strict;
use warnings;

use HTTP::Lite;

my $http = HTTP::Lite->new;
$http->http11_mode(1);

my $count = 0;
$http->request('http://www.example.com/',
    \&process_http_stream,
    \$count,
);

sub process_http_stream {
    my ($self, $data, $times) = @_;
    ++$$times;
    print "$$times====\n$$data\n===\n";
}
于 2009-10-14T17:52:59.610 回答
3

等等,我不明白。你为什么要排除一个单独的过程?这:

open my $stream, "-|", "curl $url" or die;
while(<$stream>) { ... }

对我来说,肯定看起来是“最简单的方法”。这肯定比这里的其他建议更容易......

于 2009-10-14T23:06:23.027 回答
2

Event::Lib将为您提供一个简单的接口,让您可以在您的平台上使用最快的异步 IO 方法。

IO::Lambda也非常适合创建快速、响应迅速的 IO 应用程序。

于 2009-10-14T17:54:13.150 回答
0

这是我最终通过 Net::HTTP 使用的版本

这基本上是 Net::HTTP 手册页/perl doc 中示例的副本

use Net::HTTP;

my $s = Net::HTTP->new(Host => "www.example.com") || die $@;
$s->write_request(GET => "/somestreamingdatasource.mp3");
my ($code, $mess, %h) = $s->read_response_headers;
while (1) {
  my $buf;
  my $n = $s->read_entity_body($buf, 4096);
  die "read failed: $!" unless defined $n;
  last unless $n;
  print STDERR "got $n bytes\n";
  print STDOUT $buf;
}
于 2019-10-12T01:42:37.263 回答