我可以使用HTTP :: Request :: Common :: post发送二进制变量吗?

时间:2018-03-06 12:35:41

标签: perl http gzip

我想用帖子发送我用gzip压缩过的数据 请求而不保存到文件。 在HTTP :: Request :: Common的文档中,我看到没有解释如何发布我之前制作的压缩数据。

I want to emulate this call,
curl -F "file0=@+Wowhead_Looter.lua.gz" -F "file1=@creaturecache.wdb.gz" -F "file2=@gameobjectcache.wdb.gz" \
     -F "file3=@itemcache.wdb.gz" -F "file4=@pagetextcache.wdb.gz" \
     -F "file5=@questcache.wdb.gz" "URL"

我不知道这是一次通话还是多次通话。

有人可以帮我吗?

我有这个函数读取所有文件并返回包含所有压缩文件的对象:

sub compress_wdb
{
   my ($wdb_dir,
       $wdb_dir_dh,
       @wdb_dir_files,
       $file,
       $vol,
       $dir,
       $ffile,
       %gzipped_wdb);

   $wdb_dir = shift;
   opendir $wdb_dir_dh, $wdb_dir,;
   @wdb_dir_files = grep(/^.+\..+$/, readdir $wdb_dir_dh);
   closedir $wdb_dir_dh;


   for $file (@wdb_dir_files)
   {
      gzip $wdb_dir."/".$file => \$gzipped_wdb{$file}
          or die "gzip failed: $GzipError\n";
   }

   return %gzipped_wdb;
}

稍后会调用该函数:

my %wdb = compress_wdb($wdb_dir);

然后是post函数,我有问题:

sub post
{
   my ($auth_user, $auth_password, $data, $ua, $req);

   $ua = LWP::UserAgent->new;

   $req = $ua->post("URL",
  Content_Type => 'form-data',
  Content => [
   #  $addon => [ $obj ],
  ],
);
}

这就是这样称呼的:

post(\%wdb);

1 个答案:

答案 0 :(得分:4)

附注:预先声明变量,如

   my ($wdb_dir,
       $wdb_dir_dh,
       @wdb_dir_files,
       $file,
       $vol,
       $dir,
       $ffile,
       %gzipped_wdb);

被认为是糟糕的风格。变量应该在尽可能小的范围内声明,这通常意味着它应该在第一次使用时声明。

(另外,3个空格缩进很奇怪。)

根据the curl manual-F指定了网络表单提交的字段(具体地,以multipart/form-data格式)。前缀为@的值会使curl上传文件(附加到POST请求)。

LWP::UserAgent documentation表示post方法调用了HTTP::Request::Common::POST

HTTP::Request::Common documentation for POST表示您可以通过将内容类型指定为multipart/form-data来创建'form-data'请求。它还说你可以通过指定一个数组引用作为表单字段值来进行文件上传,你可以创建一个"虚拟文件"通过设置Content伪标头(绕过从磁盘读取实际文件)。

全部放在一起:

sub post
{
    my ($files) = @_;

    my $ua = LWP::UserAgent->new;

    my $response = $ua->post(
        "YOUR URL HERE",
        Content_Type => 'form-data',
        Content => [
            do {
                my $i = 0;
                map +(
                    'file' . $i++ => [ undef, $_, Content => $files->{$_} ] 
                ),
                sort keys %$files
            }
        ],
    );

    ...
}

我们迭代%$files的键,我假设它们是压缩文件的短名称。 (我们也按字母顺序执行以使其具有确定性,这通常适用于调试。)

我们还维护一个计数器($i),我们用它来生成表单字段名称。

对于每个文件名($_存储在map中),我们会生成一个键值对。关键是表单字段名称(由field和当前计数器值组成),该值是数组引用(这是我们的文件上载规范)。

数组引用包含undef文件(因为我们不想从磁盘读取真实文件),上传文件名为$_(这就是我们想要的网页服务器将文件名视为;可能您想在此处传递"$_.gz"?),最重要的部分是$files->{$_}下存储的实际内容。

所有这一切都发生在post的调用中,这要归功于do块,这无疑是厚颜无耻的。您也可以事先创建数据结构:

my @fields;
for my $name (sort keys %$files) {
    push @fields, 'file' . @fields => [ undef, $name, Content => $files->{$name} ];
    # we don't need a counter here because we can just ask @fields how big it is
}

然后在Content => \@fields电话中传递post