Кэшировать удаленный (HTTP) запрос с помощью Transient API

8

Я пытаюсь использовать get_transient()метод в моем WordPress, я прочитал документ и, кажется, я делаю то, что было описано в документации.

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

Мы создаем локальный кеш погоды, чтобы API вызывался только по истечении времени. (Другая причина: ограничение скорости API)

Это мой код:

$country   = 'India';
$API_Key  = 'xxxxxxxxxxxxxx';
$url        = 'http://weatherAPI.com/feed/weather.ashx?q='.$latlong.'&format=json&num_of_days=4&key='.$API_Key;

$weather = get_transient($location);
if (false === $weather) {
        $ch = curl_init();
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 0);
        $weather = curl_exec($ch);
        curl_close($ch);
        set_transient($location, $weather, 60*60*6);
 }

Когда я отправляю местоположение для получения weather ( say delhi) и если его нет в кеше, я ожидал, что оно вернется, falseпока оно возвращает мне следующую строку

'{ "data": { "error": [ {"msg": "Unable to find any matching weather location to the query submitted!" } ] }}'

Я имел обыкновение var_dump($weather);проверять значение$weather

Может кто-нибудь поправить меня, где я делаю не так?

Умеш Авастхи
источник
1
Это не связано get_transient()с запросом API, как указано в сообщении об ошибке. Помимо рекомендации по использованию, wp_remote_postвам просто нужно убедиться, что отправляемый запрос является действительным.
Стивен Харрис
@StephenHarris: Я не уверен насчет звонка, так как он был дан только внутри. if (false === $weather)Я обновил мой вопрос
Умеш Авастхи
1
Суть в том, что кеш будет хранить все, что вы ему дадите - и в этом случае вы выдаете сообщение об ошибке из API погоды. Кэш вернет false только в том случае, если ничего не сохранено, поэтому вам следует проверить ответ от API погоды и, если оно действительно, сохранить его.
Стивен Харрис
@StephenHarris: ага, я понял, что твоя точка зрения полностью пропущена. Я только начал с PHP, и я просто проигнорировал все и даже не посмотрел внимательно на код :)
Umesh Awasthi

Ответы:

11

Поймать погодные API удаленных данных

То msg, что вы показываете в своем вопросе, в основном является результатом API погоды. И это говорит о том, что нет данных, доступных для вашего местоположения.

Первое, что вы хотите сделать, это некоторые исследования в Кодексе и "WP HTTP API" .

Правильный / WP способ получить удаленные данные

После того, как вы узнаете о API WP HTTP, вы увидите, что наиболее распространенный способ сделать это (упрощенно так):

$response = wp_remote_request( 'http://example.com?some=parameter', array(
    'ssl_verify' => true
) );

Если есть ошибка (как показано в вашем примере), вы сможете отловить ее, используя WP_Errorкласс:

is_wp_error( $response ) AND printf(
    'There was an ERROR in your request.<br />Code: %s<br />Message: %s',
    $response->get_error_code(),
    $response->get_error_message()
);

Тогда пришло время получить соответствующие данные. Это покажет 200и OK, если все на удаленной стороне сработало. ВАЖНО: удаленные данные, скорее всего, не будут соответствовать никаким стандартам, чем их внутренние. Так что могут быть ошибки, но вы все равно получите 200/OKот них положительное сообщение.

$response_code   = wp_remote_retrieve_response_code( $response );
$response_status = wp_remote_retrieve_response_message( $response );

Получить результат

Наконец пришло время проверить результат. Сначала мы избавляемся от пробелов в начале / конце. В следующем примере вы увидите, как использовать API-интерфейс WP HTTP для проверки заголовка. Если мы поймали JSON, то мы идем с, json_decode()и если мы получили XML, то мы идем с родным SimpleXMLклассом PHP .

// Prepare the data:
$content = trim( wp_remote_retrieve_body( $response ) );
// Convert output to JSON
if ( strstr( wp_remote_retrieve_header( $response, 'content-type' ), 'json' ) )
{
    $content = json_decode( $content );
}
// … else, after a double check, we simply go with XML string
elseif ( strstr(
        wp_remote_retrieve_header( $response, 'content-type' ),
        'application/xhtml+xml'
    ) )
{
    // Lets make sure it is really an XML file
    // We also get cases where it's "<?XML" and "<?xml"
    if ( '<?xml' !== strtolower( substr( $content, 0, 5 ) ) )
        return false;

    // Also return stuff wrapped up in <![CDATA[Foo]]>
    $content = simplexml_load_string( $content, null, LIBXML_NOCDATA );
}
// If both didn't work out, then we maybe got a CSV, or something else...

В случае CSV-файла вам нужно найти собственное решение или выполнить поиск класса PHP на веб-страницах. Но, честно говоря: если они используют CSV, проще искать другой сервис.

Кэшировать данные с помощью Transient

В пролетном API предлагает довольно хороший способ сделать это:

// Set Transient
$transient = set_transient(
    'Your cache key',
    $content,
    60*60*6
);

Затем вы должны быть в состоянии поймать переходный процесс с get_transient().

Распространенные ошибки

Часто встречающаяся ошибка заключается в том, что проверка SSL не работает. Рад, что вы можете включить / выключить его довольно легко:

// ON:
add_filter( 'https_ssl_verify', '__return_true' );
// OFF:
add_filter( 'https_ssl_verify', '__return_false' );

Есть одна довольно забавная вещь, которую вы узнаете при проверке соответствующего файла ядра: Core также получил фильтр для локальных запросов. Но не обманывайтесь этим. Этот фильтр предназначен для использования только в том случае, если вы A) предоставляете удаленный сервис из вашей установки WP и B) также используете его самостоятельно! Я знаю, что это может быть #WTF?!момент, когда вы не можете использовать различные параметры проверки SSL между вашей локальной установкой и вашей производственной средой / сервером, но у этого также есть идея: для тестирования сервисов вы представьте себя, как я уже объяснил сообществу WP G + здесь .

// Debug your own service without SSL verification.
add_filter( 'https_local_ssl_verify', '__return_false' );

Отладка запроса и его результатов

Без diggin 'слишком глубоко в процессе обновления, но API WP HTTP использует класс WP_HTTP. Это также предлагает хорошую вещь: крюк отладки.

do_action( 'http_api_debug', $response, 'response', $class, $args, $url );

Где $responseтакже может быть WP_Errorобъект, который, возможно, говорит вам больше.

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

Y НЕТ CURL?

Легко. Вся эта штука «WP HTTP API», которую я показал выше, в основном представляет собой обертку на основе функций для WP_HTTPвнутренних объектов класса, которая действует как базовый класс (и будет расширяться для различных сценариев). Выступающие WP_HTTP_*классы Fsockopen, Streams, Curl, Proxy, Cookie, Encoding. Если вы подключите обратный вызов к 'http_api_debug'-action, то третий аргумент сообщит вам, какой класс использовался для вашего запроса. Вам не нужно вызывать классы напрямую. Просто используйте функции.

Для большинства удаленных / HTTP-запросов API это WP_HTTP_curlкласс, который является оболочкой для собственной curlбиблиотеки PHP .

Внутри WP_HTTP_curlкласса вы найдете request()метод. Этот метод предлагает два фильтра для перехвата поведения SSL: один для локальных запросов 'https_local_ssl_verify'и один для удаленных запросов 'https_ssl_verify'. WP, скорее всего , определить , localкак localhostи то , что вы получите в returnс get_option( 'siteurl' );.

кайзер
источник
Примечание. Этот ответ можно считать продолжением этого ответа, который я дал .
Кайзер
Спасибо за входные данные, я не уверен насчет ответа от API-интерфейса waether, поскольку он вызывается только тогда, когда у нас нет данных, я проверил URL-адрес API и он возвращает мне действительные данные. Попробуем отладить его подробнее
Umesh Авастхи
@UmeshAwasthi Пожалуйста, попробуйте то, что я написал выше - шаг за шагом. Сначала посмотрите, что вы получите с wp_remote_request()помощью URL, а затем перейдите к ответу. Это довольно полное руководство, в котором показан правильный способ выполнения HTTP-запросов в WP. Чтобы уточнить подробнее: вам не нужно вызывать WP_HTTP_curlкласс, поскольку WordPress уже делает это за вас, когда вы используете функции, показанные выше.
Кайзер
Я нахожусь на пути, чтобы проверить это. Будет обновлено, как только я закончу это :)
Umesh Awasthi
1
Хотя проблема была в другом, но я отметил ваш ответ как принятый, поскольку он предоставляет лучший способ выполнить ту же работу, и я считаю, что если платформа предоставляет какой-то API, лучше использовать их. Спасибо!
Умеш Авастхи
3

Проблема не в функции «переходных процессов». Это похоже на сообщение об ошибке, полученное от стороннего API. Вы, вероятно, должны проверить это, прежде чем использовать set_transient. set_transientвставит все, что ему дано, и get_transientполучит все, что находится в БД. Другими словами, я уверен, что проблема не в том, что вы думаете.

$weather = get_transient($location);
if (false === $weather) {
        $ch = curl_init();
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 0);
        $weather = curl_exec($ch);
        curl_close($ch);
        // now check $weather to see if you got a valid result
        $check = json_decode($weather);
        if (isset($check->data->error)) {
          // there is a problem; do not insert; try something else
        } else {
          set_transient($location, $weather, 60*60*6);
        }
 }

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

Примечание. Ваш API возвращает JSON. Ваш пример декодирует в:

stdClass::__set_state(array(
   'data' => 
  stdClass::__set_state(array(
     'error' => 
    array (
      0 => 
      stdClass::__set_state(array(
         'msg' => 'Unable to find any matching weather location to the query submitted!',
      )),
    ),
  )),
))
s_ha_dum
источник
Спасибо за вклад, но это кажется мне довольно странным, поскольку только вызов API дается только внутри if (false === $weather)оператора. Я не знал, что WP_HTTP_curlкласс попытается это использовать
Umesh Awasthi
@UmeshAwasthi, в этом условии нет ничего странного. Если у вас есть текущие данные в кеше переходных процессов, вы не хотите получать их из API. Только если ваш кэш переходных процессов устарел, вы извлекаете новую информацию.
s_ha_dum