循环中的cURL请求有时根本不返回任何内容

时间:2019-01-14 20:15:57

标签: php json http curl error-handling

问题:

我正在使用PHP,cURL和公共API来获取json字符串。 这些json字符串的格式如下(简化后,平均大小约为50-60 kB):

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

尝试执行的操作是通过检查“ next”属性来获取从第一个字符串开始的所有json字符串。因此,我有一个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响应为null或为空,它将永远无效。触发此代码时,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 :(得分:3)

问题是您的API可能返回空响应,格式错误的JSON,甚至返回的状态代码与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; } 不同,因此您将立即停止执行。

由于您不控制API响应,因此您知道它会随机失败,并且您无权访问API服务器日志(因为您没有,对吗?);您需要在消费者中建立某种弹性。

非常的事情很简单(您需要对其进行调整)

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);

这将允许您执行类似的操作(从代码中提取):

0

我没有检查API的返回是否为非空,不是连接错误,状态是否不同于'200',并且是无效的JSON。

您可能还需要检查这些内容,具体取决于您使用的API的脆弱程度。