我们有一个基于移动设备的视频编辑器,该编辑器将人们的视频和缩略图上传到AWS S3存储桶中。然后,这将启动一个AWS SWF流程来编码,上传视频,上传缩略图并等待该视频处理,然后告诉用户他们的视频完成。每个用户都使用自己的访问令牌,以便将视频上传到自己的YouTube频道。
在过去的12个月左右的时间里,这很好,偶尔从YouTube End上传的缩略图上偶尔将后端部门扔出,我们有一个重试策略,该策略将等待1、3、8、15等。在第二或第三个重试时,YouTube服务器已经整理好了,一切都很棒。
截至2017-09-17 17:29(Aest)我们的视频都没有设法上传缩略图。系统将Google_service_exception带有503的状态代码,
的响应主体{" error":{" errors":[{{ "域":"全球", "原因":" backenderror", "消息":"后端错误"}],"代码":503,"消息":"后端错误"}}
目前,没有更新服务器软件包,我们自己的任何代码也不是任何使用的作曲家软件包。
我尝试撤销我的访问令牌,在另一个帐户上生成了自己的新项目和新的API密钥/秘密,并且仍然在我们的测试服务器上获得相同的错误处理缩略图(应该排除速率限制,我们已经很远了低于任何限制)。
视频上传仍然可以正常工作。从我们的系统编辑视频标题仍然可以正常工作(意味着访问令牌功能是功能性的,并且需要示波器t设置缩略图,如果频道允许)。直接将缩略图上传到YouTube仍然可以正常工作(排除频道本身有问题)。
我什至重新下载了示例代码并创建了一个新测试,但它仍然失败。在所有情况下,它失败的特定行是
$status = $media->nextChunk($chunk);
我不知道,如果我们目前什么都没有改变,所有图像均为1920x1080 jpg在2MB下,完全不同的项目和访问令牌,全新的示例代码。而且我假设,如果每个使用YouTube数据API的人在过去24小时内都有此错误,那么它将有更多的帖子。因此,不确定还要从我们的尽头尝试什么。
有什么建议?
编辑:好吧...这很奇怪。我设法通过卷发从服务器上的命令行上传。
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阻止或其他内容),对我们的访问令牌发出发行或向客户端键发行。它还以某种方式排除了YouTube后端的表现不佳(假设Curl和PHP通过相同的机制连接)。
只留下我的,我们将缩略图上传到YouTube(和只有缩略图)现在因没有服务器或服务器代码更改而失败,但使用命令行中的curl使用相同的访问令牌和键,可以很好地工作。p>编辑2:我已经在GitHub上上传了一个示例(包括示例图像和Composer.json文件)。它在1中有2个样本。显示YouTube PHP SDK失败的脚本,但随后使用相同的凭据成功地使用Curl请求进行了工作。脚本不包括获取访问或刷新令牌。
主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: $filesizen";
$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 successn";
}
catch (Google_Service_Exception $err)
{
echo $err->getMessage();
}
catch (Exception $err)
{
echo $err->getMessage();
}
{
"error":{
"errors":[
{
"domain":"global",
"reason":"backendError",
"message":"Backend Error"
}
],
"code":503,
"message":"Backend Error"
}
}
是Google端的服务器错误。除了等待几分钟,再试一次。通常是由于快速而引起的。
建议的操作:使用指数向后,在重试非数字请求之前包括一张支票。
实施指数退回
指数退回是针对网络应用程序的标准错误处理策略,在该应用程序中,客户会在越来越多的时间内定期检索失败的请求。如果大量的请求或繁重的网络流量导致服务器返回错误,则指数向后可能是处理这些错误的好策略。相反,这不是处理与限制费率,网络量或响应时间无关的错误的相关策略,例如无效的授权凭证或未发现错误的文件。
使用正确使用,指数向后提高了带宽使用的效率,减少了获得成功响应所需的请求数,并最大程度地提高了并发环境中请求的吞吐量。
创建请求不是愿意的。简单的重试是不够的,可能会导致重复的实体。在重试之前检查该实体是否存在。
实现简单指数退回的流量如下。
- 请求API
- 收到具有重试错误代码的错误响应
- 等待1S Random_number_milliseconds秒
- 重试请求
- 收到具有重试错误代码的错误响应
- 等待2S Random_number_milliseconds秒
- 重试请求
- 收到具有重试错误代码的错误响应
- 等待4S Random_number_milliseconds秒
- 重试请求
- 收到具有重试错误代码的错误响应
- 等待8s andur_number_milliseconds秒
- 重试请求
- 收到具有重试错误代码的错误响应
- 等待16S RONARAM_NUMBER_MILLISECONDS秒
- 重试请求
- 如果您仍然有错误,请停止并记录错误。
,而只是在不在的地方,4天后,它突然固定自身。是YT中的一个问题,但由于某种原因,无法在其所有SDK上复制的问题(例如,服务器没有触摸,远程代码突然起作用,在本地使用的测试代码突然使用)。