cURL-запрос в цикле иногда вообще ничего не возвращает - PullRequest
0 голосов
/ 14 января 2019

выпуск:

Я работаю с PHP, cURL и открытым API для извлечения строк json. Эти строки json отформатированы следующим образом (упрощенно, средний размер около 50-60 кБ):

{
   "data": {},
   "previous": "url",
   "next": "url"
}

Что я пытаюсь сделать, это получить все строки json, начиная с первой, путем проверки атрибута «next». Так что у меня есть цикл while, и пока есть атрибут «next», я получаю следующий URL.

Проблема иногда в том, что случайно цикл останавливается до конца, и я не могу понять, почему после многих тестов.

Я говорю случайно, потому что иногда цикл проходит до конца, и никаких проблем не возникает. Иногда происходит сбой после N циклов.

И до сих пор я не мог извлечь какую-либо информацию, чтобы помочь мне отладить ее.

Я использую PHP 7.3.0 и запускаю свой код из CLI.

Что я пробовал до сих пор:

Проверьте заголовки:

Заголовки не возвращаются. Вообще ничего.

Используйте curl_errno () и curl_error ():

Я попробовал следующий код сразу после выполнения запроса (curl_exec ($ ch)), но он никогда не срабатывает.

if(curl_errno($ch)) {
   echo 'curl error ' . curl_error($ch) . PHP_EOL;
   echo 'response received from curl error :' . PHP_EOL;
   var_dump($response); // the json string I should get from the server.
}

Проверьте, вернулся ли ответ null:

if(is_null($response))

или если в моей строке json есть ошибка:

if(!json_last_error() == JSON_ERROR_NONE)

Хотя я думаю, что это бесполезно, потому что оно никогда не будет действительным, если ответ cURL будет нулевым или пустым. Когда этот код срабатывает, код ошибки json равен 3 (JSON_ERROR_CTRL_CHAR)

Код проблемы:

function apiCall($url) {
   ...
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   $response = curl_exec($ch);
}
$inc = 0;
$url = 'https://api.example.com/' . $id;
$jsonString = apiCall($url);

if(!is_null($jsonString)) {
file_put_contents('pathToDirectory/' . $id + $inc, $jsonString);
$nextUrl = getNextUrl($jsonString);

    while ($nextUrl) {
        $jsonString = apiCall($url . '?page=' . $nextUrl);

        if(!is_null($jsonString)) {
            $inc++;
            file_put_contents('pathToDirectory/' . $id + $inc, $jsonString);
            $nextUrl = getNextUrl($jsonString);
        }
    }
}

Что я ожидаю от моего кода:

Не останавливаться случайно или, по крайней мере, дать мне четкий код ошибки.

1 Ответ

0 голосов
/ 15 января 2019

Проблема в том, что ваш API мог возвращать пустой ответ, искаженный JSON или даже код состояния, отличающийся от 200, и вы немедленно прекратили бы выполнение.

Поскольку вы не управляете ответами API, вы знаете, что он может случайно произойти сбой, и у вас нет доступа к журналам сервера API (потому что вы этого не делаете, не так ли?); вам нужно повысить устойчивость своего потребителя.

Что-то очень простое (вам нужно настроить его) может быть

function apiCall( $url, $attempts = 3 ) {
    // ..., including setting "$headers"
    $ch = curl_init();
    curl_setopt( $ch, CURLOPT_URL, $url );
    curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );

    for ( $i = 0; $i < $attempts; $i ++ ) {
        $response  = curl_exec( $ch );
        $curl_info = curl_getinfo( $ch );

        if ( curl_errno( $ch ) ) {
            // log your error & try again
            continue;
        }

        // I'm only accepting 200 as a status code. Check with your API if there could be other posssible "good" responses
        if ( $curl_info['http_code'] != 200 ) {
            // log your error & try again
            continue;
        }

        // everything seems fine, but the response is empty? not good.
        if ( empty( $response ) ) {
            // log your error & and try again
            continue;
        }

        return $response;
    }

    return null;
}

Это позволит вам сделать что-то вроде (извлечено из вашего кода):

do {
    $jsonString = apiCall($url . '?page=' . $nextUrl);
    $nextUrl    = false;

    if(!is_null($jsonString)) {
        $inc++;
         file_put_contents('pathToDirectory/' . $id + $inc, $jsonString);
         $nextUrl = getNextUrl($jsonString);
    }
}
while ($nextUrl);

Я не проверяю, является ли возврат из API не пустым, не ошибка соединения, состояние, отличное от '200' и , но все же недопустимый JSON.

Вы также можете проверить эти вещи, в зависимости от того, насколько хрупким является API, который вы потребляете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...