API Google PHP: неверный ответ от сервера API

Я использую Google PHP API Client v2.0 в приложении, которое я запускаю в Google App Engine на локальном хосте. Когда я публикую свое приложение в рабочей среде Google App Engine, я не получаю сообщения об ошибке, но она возникает периодически, поэтому трудно понять, повезло ли мне просто в рабочей среде.

Мой клиент API Google пытается записать файл на мой 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() необходим, потому что он работает внутри Google App Engine, который работает на PHP 5.5, который имеет испорченный пакет CA, и мне требуется предоставить правильный.

Что может быть причиной того, что он не работает для меня каждый раз, но работает для моего друга?


person Ryan Skalla    schedule 14.12.2016    source источник
comment
вам нужно будет опубликовать код, который вызывает ошибку.   -  person DaImTo    schedule 15.12.2016
comment
Это не какой-то конкретный фрагмент кода. Это происходит с перерывами и может произойти в любой строке кода, которая делает вызов API к Google. Один раз ошибка возникает в строке, которая выполняет вызов сценариев удаленных приложений, в другой раз это происходит, когда я делаю вызов Google Диска для получения списка файлов, в другой раз это происходит при вызове Google Диска для создания файла. файл. Но тогда все те же вызовы будут работать следующие 20 раз, когда я запускаю код.   -  person Ryan Skalla    schedule 16.12.2016
comment
Недостаточно информации о том, что вызывает ошибку в вопросе. Я предполагаю, что это — это клиент PHP API, который вы используете. Основываясь на ошибке fopen в коде StreamHandler, я подозреваю, что ошибка возникает либо при создании, либо при чтении файла с Диска. Пожалуйста, предоставьте минимальный пример кода, который может воспроизвести эту ошибку, и мы будем рады изучить ее.   -  person Nicholas    schedule 19.12.2016
comment
@Nicholas Я обновил блок кода, чтобы добавить минимальный пример.   -  person Ryan Skalla    schedule 22.12.2016
comment
Я не смог воспроизвести эту проблему, так как у меня нет доступа к вашему точному пакету сертификатов и другому включенному коду. Тем не менее, учитывая, что этот точный код успешно работает на устройстве вашего партнера, можно предположить, что проблема заключается либо в пакете сертификатов, либо в среде выполнения, либо в операционной системе, либо, возможно, даже в прокси-сервере. Чем они отличаются между двумя вашими системами?   -  person Nicholas    schedule 26.12.2016
comment
Я думаю, проблема с вашим $contentsarray, может быть какой-то текстовый формат или специальные символы, которые не разрешены для создания файла. Вы можете попробовать print_r($contentsarray) внутри своего catch block   -  person Aabir Hussain    schedule 27.12.2016


Ответы (1)


Прежде чем вы сможете ответить «что вызывает эту ошибку», вам сначала нужно ответить «что это за ошибка». Обычно временные сетевые ошибки являются нормальными и не приводят к падению приложения с фатальной ошибкой, даже если они происходят постоянно (например, в случае сбоя или, в вашем случае, какой-то локальной проблемы).

Guzzle, конечно же, не считает ошибки фатальными, так как устанавливает контекст HTTP по умолчанию для 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 находится где-то в самом коде приложения. Я предполагаю, что в коде приложения есть такой же тип универсального блока обработки исключений, как у вас выше, который проглатывает любой неуспешный ответ и выдает непрозрачное сообщение об ошибке как фатальное.

Лучший ответ, который я могу дать, - это найти источник сообщения об ошибке в вашем коде, а затем попросить его зарегистрировать детали, а не скрывать их, что может показать, в чем заключается основная проблема и как ее исправить.

person Adam    schedule 17.01.2017
comment
Этот ответ очень похож на то, что этого не должно происходить ... и если это произойдет, это не имеет большого значения. Не так уж и полезно. - person Kenny Wyland; 20.01.2017
comment
Нет, мой ответ заключается в том, что случайный ответ от облачного API, отличный от 200, является нормальным и должен обрабатываться корректно. Очень важно, что приложение вместо этого падает из-за указанной ошибки, как сообщает постер, но это не API, не клиентская библиотека и не SDK, которые вызывают сбой приложения, поэтому логический вывод таков: посмотрите на сам код приложения. - person Adam; 21.01.2017
comment
Но он описывает не случайную проблему, он описывает проблему, которая возникает с такой высокой частотой, что это было бы полной демонстрацией для любого производственного приложения. Код приложения приведен выше, и он не должен давать сбоев все, половину или даже треть времени. Такая частота отказов смехотворна. - person Kenny Wyland; 21.01.2017
comment
Судя по описанию, проблема локальная (происходит только на локальном хосте, у моего друга работает). Весь код приложения, очевидно, не вставлен в вопрос, поскольку это пример (например, include_once('code-base.php')). Это случай описания проблемы x, но он раскрывает другую проблему y, решение которой, вероятно, приведет к решению x. В противном случае единственным другим ответом может быть устранение неполадок в вашей локальной сети, но это не отвечает на вопрос Что такое «Неверный ответ от сервера API»? - person Adam; 23.01.2017
comment
Также да, согласен, приложение вообще не должно глючить! Он должен обрабатывать ошибки, а не аварийно завершать работу, желательно протоколировать или сообщать как можно больше подробностей об ошибках, что поможет выявить основную причину. Суть этого вопроса в том, почему он этого не делает и каков источник этого загадочного сообщения об ошибке. - person Adam; 23.01.2017
comment
Invalid response from API server не является ошибкой, существующей где-либо в коде приложения. Я выполнил полный поиск проекта для Invalid response с помощью PHPStorm, и он ничего не дал, и даже сделал fgrep -R "Invalid response" * из командной строки в корне проекта (на всякий случай, если PHPStorm скрывал некоторые результаты), и он также не нашел эту строку. Это сообщение об ошибке исходит не от меня - person Ryan Skalla; 23.01.2017