我正在尝试用 Perl 实现 Google 的 YouTube 视频上传 API,可惜没有这样的库。我在上传视频文件时遇到了实际的
PUT
问题。 LWP::UserAgent
有一个非常有用的功能,可以通过简单地在 arrayref 中引用文件名来避免流式上传大文件,如下所示:
my $ua = LWP::UserAgent->new;
my $upload_url = "https://myapi";
my $localPath = "myBigVideoFile.mp4";
my $upload_response = $ua->put( $upload_url, 'Content_Type' => 'form-data', 'Content' => [ 'file' => [ $localPath ] ] );
但是,这不是 Google API 期望的格式。它希望 Content-Type 为“video/*”,并且希望响应的整个正文都是文件,而不是将其隐藏为表单中的“文件”字段。但更改代码以符合 Google 的期望会禁用 LWP 方便的文件加载功能。例如:
my $upload_response = $ua->put( $upload_url, 'Content_Type' => 'video/*', 'Content' => [ $localPath ] );
在这种情况下,LWP 请求对象仅将文件名显示为内容,而不是流式传输内容。
有什么方法可以激活LWP的文件加载魔法,或者轻松模拟它,这样我就可以实现Google的所需格式,而无需预加载整个文件(显然不是一个好主意!)。
这是 Google 需要的 HTTP 格式:
PUT API_ADDRESS_GOES_HERE HTTP/1.1
Authorization: Bearer AUTH_TOKEN_GOES_HERE
Content-Length: CONTENT_LENGTH_GOES_HERE
Content-Type: video/*
BINARY_FILE_DATA
(在实际代码中,我在
LWP::Authen::OAuth2
之上使用 LWP::UserAgent
,但是当我使用 just UserAgent 将数据发送到我自己的端点时,我上面概述的所有内容都会发生。
这可能不是最好的答案(我很想听到一个更优雅并触发 LWP 内置功能的建议),但我已经通过打开文件句柄并将句柄传递给
$ua->content
成功获得了一个可行的解决方案
间接使用匿名子例程来读取它(直接传递文件句柄并没有像我希望的那样工作):
$request->content(sub {
my $buffer;
my $bytes_read = read($fh, $buffer, 8192);
return $bytes_read ? $buffer : undef;
});
在最终代码中,这需要从 OAuth2 对象获取用户代理并手动完成工作。
my $ua = $oauth2->user_agent();
my $upload_response = $ua->request($request);
LWP::Authen::OAuth2
有一个内置的 request
函数,旨在中继到 LWP::UserAgent
,但使用该函数(而不是检索 $ua
并直接进行调用)会导致错误:
Can't store CODE items at /Users/timothybutler/perl5/perlbrew/perls/perl-5.36.0/lib/site_perl/5.36.0/LWP/Authen/OAuth2/AccessToken/Bearer.pm line 13.