获取HTTP代码状态并重试Outlook Api

时间:2017-11-03 13:15:53

标签: php curl http-headers

我有这个URL,我可以从Outlook获取事件:

// ! API sorting by Id doesn't work so we'll have to implement it ourselves.
    $url = 'https://outlook.office365.com/api/v2.0/users/' . $this->user . '/CalendarView/'
        . '?startDateTime=' . $start_datetime
        . '&endDateTime=' . $end_datetime
        .'&$top=100';

我对此很陌生,现在我正在努力得到如下答案:

    $http = new \Http_Curl();
    $http->set_headers( $this->get_headers() );
    $response = $http->get( $url );

where I have this `HTTP_CURL` class that contains methods as below:



public function get( $url ) {
            return $this->request( $url, 'GET', $this->headers );
        }

private function request( $url, $method, $headers, $data = false ) {
        $handle = curl_init();
        curl_setopt( $handle, CURLOPT_URL, $url );
        curl_setopt( $handle, CURLOPT_SSL_VERIFYPEER, false );
        curl_setopt( $handle, CURLOPT_RETURNTRANSFER, true );

        if ( $this->headers )
            curl_setopt( $handle, CURLOPT_HTTPHEADER, $this->headers );

        curl_setopt( $handle, CURLOPT_VERBOSE, true );
        curl_setopt( $handle, CURLINFO_HEADER_OUT, true );

        switch ( $method ) {
            case 'POST':
                curl_setopt( $handle, CURLOPT_POST, true );
                curl_setopt( $handle, CURLOPT_POSTFIELDS, $data );
                break;
            case 'PATCH':
                curl_setopt( $handle, CURLOPT_POSTFIELDS, $data );
                curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, 'PATCH' );
                break;
            case 'DELETE':
                curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, 'DELETE' );
                break;
        }

        $http_response = curl_exec( $handle );

        curl_close( $handle );

        return json_decode( $http_response );
    }

我需要的是在响应中获取HTTP错误代码。 根据Outlook HTTP 429 Too Many Requests响应状态代码表示用户在给定的时间内发送了太多请求("速率限制")。此响应中可能包含Retry-After标头,指示在发出新请求之前需要等待多长时间。

那么如何获取此HTTP错误代码和Retry-After?喜欢这个链接:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429

我尝试过这一行:$httpcode = curl_error($url, CURLINFO_HTTP_CODE); 我一直都是空的。

1 个答案:

答案 0 :(得分:1)

您在curl_error功能中使用了无效参数。应该是curl_error($handle)

最好的方法是使用Guzzle PHP HTTP客户端。它有methods for getting response headers。您可以使用this perfect example发出重复请求:

<?php
require './vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;

class TestRetry {

    public function test()
    {
        $handlerStack = HandlerStack::create(new CurlHandler());
        $handlerStack->push(Middleware::retry($this->retryDecider(),
        $this->retryDelay()));
        $client = new Client(array('handler' => $handlerStack));

        $response = $client->request(
            'GET',
            // @todo replace to a real url!!!
            'https://500-error-code-url'
        )->getBody()->getContents();

        return \GuzzleHttp\json_decode($response, true);
    }


    public function retryDecider()
    {
        return function (
            $retries,
            Request $request,
            Response $response = null,
            RequestException $exception = null
        ) {
            // Limit the number of retries to 5
            if ($retries >= 5) {
                return false;
            }

            // Retry connection exceptions
            if ($exception instanceof ConnectException) {
                return true;
            }

            if ($response) {
                // Retry on server errors
                if ($response->getStatusCode() >= 500 ) {
                    return true;
                }
            }

            return false;
        };
    }

    /**
     * delay 1s 2s 3s 4s 5s
     *
     * @return Closure
     */
    public function retryDelay()
    {
        return function ($numberOfRetries) {
            return 1000 * $numberOfRetries;
        };
    }
}

$TestRetry = new TestRetry();
$TestRetry->test();

我为您的案例略微更改了此代码:

<?php
require './vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;

class MyOutlookApiClient {

    const BASE_API_URL = 'https://outlook.office365.com/api/v2.0';
    public $user;
    protected $retryOnErrors;
    protected $retryMaxCount;

    /**
     * @param $user
     */
    public function __construct($user)
    {
        $this->user = $user;
    }

    /**
     * @param array $retryOnErrors
     * @return $this
     */
    public function setRetryOnErrors($retryOnErrors=[])
    {
        $this->retryOnErrors = $retryOnErrors;
        return $this;
    }

    /**
     * @param $retryMaxCount
     * @return $this
     */
    public function setRetryMaxCount($retryMaxCount = 5)
    {
        $this->retryMaxCount = $retryMaxCount;
        return $this;
    }

    /**
     * @param $startDatetime
     * @param $endDatetime
     * @param $top
     * @return mixed
     */
    public function getUsersCalendarView($startDatetime, $endDatetime, $top)
    {
        $handlerStack = HandlerStack::create(new CurlHandler());
        $handlerStack->push(Middleware::retry($this->retryDecider(),
            $this->retryDelay()));
        $client = new Client(array('handler' => $handlerStack));

        $calendarViewUrl = self::BASE_API_URL.'/users/'.$this->user.'/CalendarView/';
        $queryParams = [
            'startDateTime' => $startDatetime,
            'endDateTime' => $endDatetime,
            'top' => $top
        ];
        $response = $client
            ->request('GET', $calendarViewUrl, ['query' => $queryParams])
            ->getBody()
            ->getContents();

        return \GuzzleHttp\json_decode($response, true);
    }

    /**
     * @return Closure
     */
    public function retryDecider()
    {
        return function (
            $retries,
            Request $request,
            Response $response = null,
            RequestException $exception = null
        ) {
            // Limit the number of retries to 5
            if ($retries >= $this->retryMaxCount) {
                return false;
            }

            // Retry connection exceptions
            if ($exception instanceof ConnectException) {
                return true;
            }

            if ($response) {
                // Retry on server errors
                $responseCode = $response->getStatusCode();
                if (
                    ($this->retryOnErrors && in_array($responseCode, $this->retryOnErrors))
                    || ($responseCode >= 500)
                ) {
                    return true;
                }
            }

            return false;
        };
    }

    /**
     * delay 1s 2s 3s 4s 5s
     *
     * @return Closure
     */
    public function retryDelay()
    {
        return function ($numberOfRetries) {
            return 1000 * $numberOfRetries;
        };
    }
}

// your code to init variables here
// ...

$myOutlookApiClient = new MyOutlookApiClient($user);
$myOutlookApiClient
    ->setRetryOnErrors([429])
    ->setRetryMaxCount(5)
    ->getUsersCalendarView($startDatetime, $endDatetime, $top);