Как мне выполнить загрузку с кодированной передачей с помощью 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? Есть ли какая-то другая хитрость? Google не проливает много света на это, Perlmonks тоже, а документация немного тупая.

2 ответа

Решение

Вы можете сделать это используя 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;

Вы действительно нуждаетесь WWW::Mechanize? Это подкласс LWP::UserAgent с дополнительными функциями, которые предоставляют функции, аналогичные браузеру, такие как заполнение и отправка форм, переход по ссылкам, история страниц с операцией "назад" и т. д. Если вам все это не нужно, вы также можете использовать LWP::UserAgent непосредственно

В любом случае, post метод наследуется без изменений от LWP::UserAgentи можно использовать его напрямую, как вы сделали

Способ отправить чанк POST это установить Content на ссылку на подпрограмму. Подпрограмма должна возвращать следующий фрагмент данных каждый раз, когда она вызывается, и, наконец, ann пустую строку или undef когда больше нечего отправить

Должны ли данные быть строкой JSON?

Проще всего написать фабричную подпрограмму, которая возвращает замыкание, как это

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)
);

Пожалуйста, имейте в виду, что все это не проверено

Другие вопросы по тегам