Кэшировать удаленный (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!',
      )),
    ),
  )),
))

Спасибо за вклад, но это кажется мне довольно странным, поскольку только вызов API дается только внутри if (false === $weather)оператора. Я не знал, что WP_HTTP_curlкласс попытается это использовать
Umesh Awasthi

@UmeshAwasthi, в этом условии нет ничего странного. Если у вас есть текущие данные в кеше переходных процессов, вы не хотите получать их из API. Только если ваш кэш переходных процессов устарел, вы извлекаете новую информацию.
s_ha_dum
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.