我们有一个基于移动设备的视频编辑器,可将人们的视频和缩略图上传到AWS S3存储桶。然后启动AWS SWF流程以编码,上传视频,上传缩略图并等待处理所述视频,然后告知用户他们的视频已完成。每个用户都使用自己的访问权限,以便将视频上传到自己的YouTube频道。
这在过去的12个月左右一直没问题,偶尔会在YouTube结尾处上传缩略图上的后端错误,我们有一个等待1,3,8,15等秒的重试策略。通过第二次或第三次重试,YouTube服务器已经整理好了,一切都很好。
截至2017-09-17 17:29(AEST)我们的视频均无法上传缩略图。系统抛出Google_Service_Exception,状态代码为503,响应正文为
{“error”:{“errors”:[{ “域名”:“全球”, “reason”:“backendError”, “message”:“Backend Error”}],“code”:503,“message”:“Backend Error”}}
此时,没有更新任何服务器软件包,也没有更新任何我们自己的代码或使用过的composer软件包。
我尝试撤销我的访问令牌,在另一个帐户上生成了我自己的新项目和新的API密钥/机密,并且在我们的测试服务器上仍然得到相同的错误处理缩略图(应该排除速率限制,我们很远低于任何限制)。
视频上传仍然正常。从我们的系统编辑视频标题仍然可以正常工作(意味着访问令牌功能正常,并且如果频道允许,则需要范围设置缩略图)。手动将缩略图直接上传到YouTube仍然可以正常工作(排除通道本身存在问题)。
我甚至重新下载了sample code并创建了一个新的测试但它仍然失败了。在所有情况下它失败的具体线是
$status = $media->nextChunk($chunk);
我不知道是什么原因导致这个突然问题,如果我们的结果没有任何改变,所有图像都是1920x1080 jpgs远低于2mb,完全不同的项目和访问令牌,全新的示例代码。我假设如果所有使用YouTube数据API的人都在过去24小时内收到此错误,那么会有更多关于它的帖子。所以不确定还有什么可以尝试。
有什么建议吗?
编辑: 嗯......这很奇怪。我设法通过命令行从我们的服务器上传cURL。
curl -X POST -F "image=@thumbnail_test.jpg" "https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=dCdQ2tJ5wIs&key={REMOVED}&access_token={REMOVED}"
这很好。因此,排除我们的服务器问题(IP阻止或某些东西),我们的访问令牌问题或我们的client_id密钥问题。它还以某种方式排除了YouTube后端表现不佳(假设cURL和php通过相同的机制连接)。
这只留给我,我们将缩略图上传到YouTube(并且只有缩略图)现在从PHP失败而没有服务器或服务器代码更改,但在命令行中通过cURL使用相同的访问权限和密钥工作正常。
编辑2: 我上传了一个示例here on github(包括示例图像和composer.json文件)。它在2中有2个样本。显示脚本使用youtube php sdk失败,但随后使用相同的凭据成功处理卷曲请求。脚本不包括获取访问权限或刷新令牌。
主要的test.php脚本如下。
<?php
define('GOOGLE_CLIENT_ID', 'REPLACE_ME');
define('GOOGLE_CLIENT_SECRET', 'REPLACE_ME');
require_once 'vendor/autoload.php';
$token = [
'access_token' => 'REPLACE_ME',
'refresh_token' => 'REPLACE_ME',
'token_type' => 'Bearer',
'expires_in' => '3600',
'created' => REPLACE_ME
];
$youtube_id = 'REPLACE_ME';
$thumbnail_path = realpath('thumbnail.jpg');
/*
// Doing the exact same request in cURL works fine.
$data = [
'filedata' => new CURLFile($thumbnail_path, 'image/jpeg', basename($thumbnail_path)),
];
// Execute remote upload
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, [
'Authorization: Bearer '.$token['access_token'],
]);
curl_setopt($curl, CURLOPT_URL, 'https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId='.$youtube_id.'&key='.GOOGLE_CLIENT_SECRET);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_VERBOSE, 1);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
*/
// Based on php sample from https://developers.google.com/youtube/v3/docs/thumbnails/set
$client = new Google_Client();
$client->setClientId(GOOGLE_CLIENT_ID);
$client->setClientSecret(GOOGLE_CLIENT_SECRET);
$client->setScopes([
'https://www.googleapis.com/auth/yt-analytics.readonly',
'https://www.googleapis.com/auth/youtube',
'https://www.googleapis.com/auth/youtube.upload',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
]);
$client->setAccessType('offline');
// If you want to use a refresh token instead to get an access token from it.
//$token = $client->fetchAccessTokenWithRefreshToken($refresh_token);
//var_dump($token);
$client->setAccessToken($token);
$service = new Google_Service_YouTube($client);
try
{
// Specify the size of each chunk of data, in bytes. Set a higher value for
// reliable connection as fewer chunks lead to faster uploads. Set a lower
// value for better recovery on less reliable connections.
$chunkSizeBytes = 1 * 1024 * 1024;
// Create a MediaFileUpload object for resumable uploads.
// Parameters to MediaFileUpload are:
// client, request, mimeType, data, resumable, chunksize.
$client->setDefer(true);
$request = $service->thumbnails->set($youtube_id);
$client->setDefer(false);
$mimeType = 'image/jpeg';
$media = new Google_Http_MediaFileUpload(
$client,
$request,
$mimeType,
null,
true,
$chunkSizeBytes
);
$filesize = filesize($thumbnail_path);
echo "Filesize: $filesize\n";
$media->setFileSize($filesize);
// Read the media file and upload it chunk by chunk.
$status = false;
$handle = fopen($thumbnail_path, "rb");
while (!$status && !feof($handle))
{
$chunk = fread($handle, $chunkSizeBytes);
$status = $media->nextChunk($chunk); // The line where the Google_Service_Exception exception is thrown.
}
fclose($handle);
echo "Thumbnail uploaded success\n";
}
catch (Google_Service_Exception $err)
{
echo $err->getMessage();
}
catch (Exception $err)
{
echo $err->getMessage();
}
答案 0 :(得分:0)
* as All
Googles方面是服务器错误。除了等几分钟再试一次,你真的没什么可做的。这通常是由于快速造成的。
建议采取的措施:使用exponential backoff,在重试非幂等请求之前包含一项检查。
实施指数退避
指数退避是网络应用程序的标准错误处理策略,其中客户端会在不断增加的时间内定期重试失败的请求。如果大量请求或繁重的网络流量导致服务器返回错误,则指数退避可能是处理这些错误的好策略。相反,它不是处理与速率限制,网络量或响应时间无关的错误的相关策略,例如无效的授权凭证或未找到文件的错误。
正确使用,指数退避可提高带宽使用效率,减少获得成功响应所需的请求数,并最大化并发环境中请求的吞吐量。
创建请求不是幂等的。简单的重试是不够的,可能导致重复的实体。在重试之前检查实体是否存在。
实现简单指数退避的流程如下:
答案 1 :(得分:0)
就在没有的地方,4天后它突然修复了自己。在YT中是一个问题,但由于某些原因,它不是可以在所有SDK中复制的问题(因为同样,服务器没有被触及,远程代码突然起作用,本地使用的测试代码突然起作用)。