Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: Ryan SkallaОтветов: 1

Я использую 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, и мне требуется предоставить правильный.

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

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

phpgoogle-apigoogle-app-enginegoogle-drive-apigoogle-api-php-client

Ответы

Ответ 1 · рейтинг -1 · Adam

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

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы