【发布时间】:2009-10-14 17:46:37
【问题描述】:
在 Perl 中从另一个 HTTP 资源流式传输的最简单方法是什么(无需打开 shell 来 curl 并从标准输入中读取)?我在这里假设我正在读取的 HTTP 资源是一个潜在的无限流(或者只是非常非常长)
【问题讨论】:
标签: perl http streaming mod-perl
在 Perl 中从另一个 HTTP 资源流式传输的最简单方法是什么(无需打开 shell 来 curl 并从标准输入中读取)?我在这里假设我正在读取的 HTTP 资源是一个潜在的无限流(或者只是非常非常长)
【问题讨论】:
标签: perl http streaming mod-perl
良好的旧 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
}
【讨论】:
LWP 和 LWP::Simple 是不同的野兽。
HTTP::Lite 的request 方法允许您指定回调。
$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";
}
【讨论】:
request 的回调函数的处理方式与使用set_callback 设置的回调函数不同,并且文档没有正确解释这一点。
等等,我不明白。你为什么要排除一个单独的过程?这个:
open my $stream, "-|", "curl $url" or die;
while(<$stream>) { ... }
对我来说,这确实是“最简单的方法”。这肯定比这里的其他建议更容易......
【讨论】:
Event::Lib 将为您提供一个简单的接口,让您可以使用适合您平台的最快异步 IO 方法。
IO::Lambda 也非常适合创建快速、响应迅速的 IO 应用程序。
【讨论】:
这是我最终通过 Net::HTTP 使用的版本
这基本上是 Net::HTTP 手册页/perl 文档中示例的副本
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;
}
【讨论】: