Perl www::curl-如何上传(发布)大文件

Perl www::curl-如何上传(发布)大文件,perl,file-upload,curl,libcurl,Perl,File Upload,Curl,Libcurl,我使用WWW::Curl上载文件: use WWW::Curl::Easy 4.14; use WWW::Curl::Form; my $url = 'http://example.com/backups/?sid=12313qwed323'; my $params = { name => 'upload', action => 'keep', backup1 => [ '/tmp/backup1.zip' ], # 1st file for up

我使用WWW::Curl上载文件:

use WWW::Curl::Easy 4.14;
use WWW::Curl::Form;

my $url = 'http://example.com/backups/?sid=12313qwed323';
my $params = {
    name => 'upload',
    action => 'keep',
    backup1 => [ '/tmp/backup1.zip' ],   # 1st file for upload
};

my $form = WWW::Curl::Form->new();
foreach my $k (keys %{$params}) {
    if (ref $params->{$k}) {
        $form->formaddfile(@{$params->{$k}}[0], $k, 'multipart/form-data');
    } else {
        $form->formadd($k, $params->{$k});
    }
}

my $curl = WWW::Curl::Easy->new() or die $!; 
$curl->setopt(CURLOPT_HTTPPOST, $form);
$curl->setopt(CURLOPT_URL, $url);

my $body;   
$curl->setopt(CURLOPT_WRITEDATA, \$body);
my $retcode = $curl->perform();
my $response_code = $curl->getinfo(CURLINFO_HTTP_CODE); 
这里没有什么特别的,这段代码运行良好

我想上传大文件,我不想预装内存中的所有内容。至少我听说libcurl正在这么做

CURLOPT_READFUNCTION接受返回部分内容的回调。这意味着我不能使用WWW::Curl::Form来设置POST参数,但我必须通过这个回调返回整个内容。是这样吗

我认为代码可以如下所示:

use WWW::Curl::Easy 4.14;

my $url = 'http://example.com/backups/?sid=12313qwed323'
my $params = {
    name => 'upload',
    action => 'keep',
    backup1 => [ '/tmp/backup1.zip' ],   # 1st file for upload
};

my $fields;
foreach my $k (keys %{$params}) {
    $fields .= "$k=".(ref $params->{$k} ? '@'.@{$params->{$k}}[0] : uri_escape_utf8($params->{$k}))."&";
}
chop($fields);

my $curl = WWW::Curl::Easy->new() or die $!;
$curl->setopt(CURLOPT_POST, 1);
$curl->setopt(CURLOPT_POSTFIELDS, $fields); # is it needed with READFUNCTION??
$curl->setopt(CURLOPT_URL, $url);

my @header = ('Content-type: multipart/form-data', 'Transfer-Encoding: chunked');
$curl->setopt(CURLOPT_HTTPHEADER, \@header);

#$curl->setopt(CURLOPT_INFILESIZE, $size);
$curl->setopt(CURLOPT_READFUNCTION, sub {

    # which data to return here?
    # $params (without file) + file content?

    return 0;
});
CURLOPT_READFUNCTION回调必须返回哪些数据$参数+文件内容?哪种格式

我真的必须自己创建数据(由CURLOPT_READFUNCTION返回),还是有一种简单的方法以正确的格式创建它

谢谢

测试是相关的。正如你所看到的,它完全被禁用了。这一事实以及我对回调函数的各种返回值进行的徒劳实验让我相信
CURLOPT_READFUNCTION
特性在Perl绑定中已被破坏

我必须通过这个回调返回全部内容。是这样吗

不,您可以分段地将请求主体提供给它,适合分块编码。根据
CURLOPT\u infiresize
中设置的限制,回调必须调用多次

CURLOPT_READFUNCTION回调必须返回哪些数据

HTTP请求主体。既然你上传了文件,这意味着。下面是一个使用HTTP::Message的示例。是构造此格式的另一种方法

use HTTP::Request::Common qw(POST);
use WWW::Curl::Easy 4.14;

my $curl = WWW::Curl::Easy->new or die $!;
$curl->setopt(CURLOPT_POST, 1);
$curl->setopt(CURLOPT_URL, 'http://localhost:5000');
$curl->setopt(CURLOPT_HTTPHEADER, [
    'Content-type: multipart/form-data', 'Transfer-Encoding: chunked'
]);
$curl->setopt(CURLOPT_READFUNCTION, sub {
    return POST(undef, Content_Type => 'multipart/form-data', Content => [
        name    => 'upload',
        action  => 'keep',
        backup1 => [ '/tmp/backup1.zip' ],   # 1st file for upload
    ])->content;
});
my $r = $curl->perform;

CURLOPT_READFUNCTION回调仅用于分块传输编码。它可能会起作用,但我一直没能把它送到,我发现这样做是没有必要的

我的用例是将数据上传到AWS,在AWS中,将数据作为多部分表单数据上传是不合适的。相反,这是一个直接的数据发布。不过,它确实要求您知道要向服务器发送多少数据。这似乎对我有用:

my $infile = 'file-to-upload.json';
my $size = -s $infile;
open( IN, $infile ) or die("Cannot open file - $infile. $! \n");

my $curl = WWW::Curl::Easy->new;
$curl->setopt(CURLOPT_HEADER,       1);
$curl->setopt(CURLOPT_NOPROGRESS,   1);
$curl->setopt(CURLOPT_POST,         1);
$curl->setopt(CURLOPT_URL,          $myPostUrl);
$curl->setopt(CURLOPT_HTTPHEADER,   
    ['Content-Type: application/json']); #For my use case
$curl->setopt(CURLOPT_POSTFIELDSIZE_LARGE, $size);
$curl->setopt(CURLOPT_READDATA, \*IN);

my $retcode = $curl->perform;

if ($retcode == 0) {
    print("File upload success\n");
} 
else {
    print("An error happened: $retcode ".$curl->strerror($retcode)."\n");
}

关键是提供对CURLOPT_READDATA的开放文件句柄引用。之后,core curl库处理从它读取的数据,而不需要任何回调。

您是否承诺使用WWW::curl?我认为,如果您可以使用switch.LWP或更好地使用WWW::mechanizi,使用LWP会更容易。我知道这个答案与您的代码没有直接关系,但我花了大量时间使用WWW::Mechanize解决类似问题,结果发现web服务器上的MaxPostSize已被管理员设置为任意限制。我已经使用LWP完成了这项工作,它比libcurl慢得多。我将检查WWW::Mechanize。谢谢,谢谢。非常有用的信息。HTTP::Message的问题在于它将整个内容加载到内存中。我的内存有限(64MB),这意味着请求必须小得多。今天,我将尝试创建一个回调函数,该函数以块的形式返回内容,而不缓冲整个内容。刚刚从WWW::Curl维护者那里收到关于CURLOPT_READFUNCTION功能的消息:“是的,看起来很糟糕。我计划在未来几周内对WWW::Curl进行彻底检查,可能也会解决这个问题。”你认为它为什么会坏?我对READFUNCTION没有任何问题,它的行为完全符合curl主页上的解释。“它对我有用”;-)确认:当您运行它时,我的答案中的程序会传输一个非空的请求正文。如果没有更多的字节可返回,READFUNCTION必须返回0。我对“传输编码:分块”有问题,因为服务器响应“内容长度丢失”,尽管它是分块传输。我删除了标题行,它的工作。