如何使用 WWW:Mechanize 进行分块 transfer-encoding 上传?

How do I do a chunked transfer-encoding upload with WWW:Mechanize?

我正在尝试使用特定的网络服务,我可以使用以下命令成功执行上传:

curl -X POST  --header "Transfer-Encoding: chunked" -d @Downloads/file.pdf https://some.webservice/upload

我收到一个 json 响应表明成功。

但是,我不知道如何用 WWW::Mechanize 做同样的事情。

$mech->post("https://" . $server . "/upload", Content_Type => 'multipart/form-data', Content => [upID => $upid, name => $dlfile, userID => 0, userK => 0, file_0 => [$dlfile]]);

这会收到类似的 json 响应,其中包含一条大错误消息。

我需要先明确设置 Transfer-Encoding header 吗?还有其他技巧吗? Google 对此没有太多说明,Perlmonks 也没有,而且文档有点迟钝。

你真的需要WWW::Mechanize吗?它是 LWP::UserAgent 的子类,具有附加功能,可提供类似浏览器的功能,例如填写和提交表单、单击链接、具有 "back" 操作的页面历史记录等。如果您不需要全部那么你也可以直接使用LWP::UserAgent

无论哪种方式,post方法都是继承自LWP::UserAgent,原封不动的,直接用就好了

发送分块 POST 的方法是将 Content 设置为对子例程的引用。子例程每次调用时必须 return 下一个数据块,最后一个空字符串或 undef 当没有更多要发送时

数据应该是 JSON 字符串吗?

写一个 return 是一个闭包的工厂子例程是最简单的,就像这样

sub make_callback {
    my ($data) = shift;
    sub { substr($data, 0, 512, "") }
}

然后你可以这样调用post

my $payload = to_json(...);

$mech->post(
    "https://$server/upload",
    Content_Type => 'multipart/form-data',
    Content      => make_callback($payload)
);

请注意,所有这些都未经测试

您可以使用 HTTP::Request::StreamingUpload

my $starttime = time();
my $req = HTTP::Request::StreamingUpload->new(
    POST     => $url,
    path    => $file,
    headers => HTTP::Headers->new(
        'Transfer-Encoding' => 'chunked' 
    ),
);

my $gen = $req->content;
die unless ref($gen) eq "CODE";

my $total = 0;
$req->content(sub {
    my $chunk = &$gen();
    $total += length($chunk);

    print "\r$total / $size bytes ("
        . int($total/$size*100)
        . "%) sent, "
        . int($total/1000/(time()-$starttime+1))
        . " k / sec ";

    return $chunk;
});

my $resp = $ua->request($req);
print "\n";

unless ($resp->is_success) {
    die "Failed uploading the file: ", $resp->status_line;
}

my $con = $resp->content;
return $con;