我在我在localhost上的Google App Engine上运行的应用中使用Google PHP API Client v2.0。当我将我的应用程序发布到Google App Engine生产时,我没有收到错误,但它是间歇性的,因此很难知道我是否只是在生产中变得幸运。
我的Google API客户端正在尝试将文件写入我的Google云端硬盘。这段代码已经运行了好几个月,但它今天早上突然停止工作。我检查了Google API状态,但他们没有报告任何中断。当我执行任何API调用时,我得到了这个模糊的错误响应:
致命错误:fopen():来自API服务器的响应无效。在 /Users/me/googleappengine/stuff-otherstuff-111111/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php 的 在线 312
该文件确实是在Google云端硬盘上创建的,因此我的API调用正在通过,但无论回复到我的脚本的任何响应都会导致致命的崩溃。
几分钟后它再次开始工作,现在又崩溃了。我无法在任何地方找到错误Invalid response from API server
的任何解决方案......而且它是间歇性的。它似乎与我的代码无关,但Google表示它没有任何中断。
我错过了什么?我该如何解决这个问题?
<?php
include_once('code-base.php');
require_once('vendor/autoload.php');
$client = new Google_Client();
$client->setApplicationName(getSetting('APP_NAME'));
$client->setAuthConfig(json_decode(getSetting('localhost_google_client_secret'), true));
$client->setAccessType("offline");
$client->setScopes(array(Google_Service_Drive::DRIVE));
$client->setHttpClient(new GuzzleHttp\Client(['verify'=>'ca-bundle.crt']));
$accesstoken = json_decode(getSetting('localhost_google_oauth_token'), true);
$client->setAccessToken($accesstoken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
print "access token is expired\n";
$refreshtoken = getSetting('localhost_google_refresh_token');
print "refresh token: $refreshtoken\n";
$client->refreshToken($refreshtoken);
$newtokenjson = json_encode($client->getAccessToken());
print "new token: $newtokenjson\n";
printf("before: %s\n\nafter: %s\n\n", $accessToken, $newtokenjson);
//file_put_contents($credentialsPath, $newtokenjson);
updateSetting('localhost_google_oauth_token', $newtokenjson);
}
print "after checking access token expired\n";
print "before drive service\n";
$driveservice = new Google_Service_Drive($client);
print "after drive service\n";
$parentfolderid = getSetting('GDRIVE_EXPORT_DUMP');
$title = "00005 test gdrive.csv";
$filetype = 'text/csv';
$contents = "The quick brown fox jumped over the lazy dog.";
$file = new Google_Service_Drive_DriveFile();
$file->setName($title);
$file->setDescription($title);
$file->setMimeType($filetype);
$file->setParents(array($parentfolderid));
try {
if ($contents == null) {
print "contents of file are null, creating empty file\n";
$createdFile = $driveservice->files->create($file);
print "after creating empty file\n";
} else {
$contentsarray = array('data' => $contents, 'mimeType' => $filetype, 'uploadType' => 'media');
if ($options != null) {
foreach($options as $key => $value) {
$contentsarray[$key] = $value;
}
}
print "file contents: ".var_export($contentsarray, true)."\n";
$createdFile = $driveservice->files->create($file, $contentsarray);
print "after create file with contents\n";
}
return $createdFile;
} catch (Exception $e) {
print "EXCEPTION: An error occurred: " . $e->getMessage()."\n";
}
编辑:我的代码现在似乎与Invalid response from API server
消息一致失败。它只会在代码与Google通信时失败。这两个地方是我打电话给refreshToken()
(很少见),另一个是我打电话给create()
的时候。
我让我的朋友在他的机器上使用相同的设置运行这个确切的代码(据我们所知...相同的代码,相同的库,相同的oauth令牌等)并且它适用于他。
注意:getSetting()
函数上面的代码只是从我的数据库中提取一些我用于配置目的的字符串。另外,需要进行setHttpClient()
调用,因为这是在运行在PHP 5.5上的Google App Engine中运行的,它有一个搞砸的CA Bundle,它需要我提供一个正确的。
什么可能导致它每次都失败,但为我的朋友工作?
答案 0 :(得分:-1)
在您回答“造成此错误的原因”之前,您首先需要回答“错误是什么”。通常,瞬态网络错误是正常的,并且不会强制应用程序因致命错误而崩溃,即使它们经常发生(例如,在发生中断或在您的情况下,某些本地问题)。
Guzzle肯定不会将错误视为致命错误,因为sets its default HTTP context to ignore_errors => true(并且无论如何都会返回响应)。 google-api-php-client
不会更改ignore_errors
的默认行为,也不会更改google-api-php-client-services
,开发服务器和PHP SDK的默认行为。文本Invalid response from API server
不会出现在任何上述项目的源代码中的任何位置,也不是来自任何API的文档错误响应。
因此,它会建议Invalid response from API server
的源位于应用程序代码本身的某个位置。我的猜测是,应用程序代码中存在类似类型的catch-all异常处理块,就像你上面吞下任何类型的非成功响应一样,并且使用不透明的错误消息作为致命错误。
我能给出的最佳答案是在代码中查找错误消息的来源,然后告诉它记录详细信息而不是模糊它们,这可能会揭示底层问题是什么以及如何解决它。