使用Transients API缓存远程(HTTP)请求


8

我正在尝试get_transient()在Wordpress中使用method,我已经阅读了文档,似乎在做文档中描述的操作。

我需要在网站上显示天气,并且我正在使用每6小时更新一次的第三方天气API。

我们正在创建本地天气缓存,以便仅在到期后调用该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);
 }

当我发送一个要获取天气(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)。我已更新了我的问题
Umesh Awasthi 2012年

1
关键是缓存将存储您提供的所有内容-在这种情况下,您将给出来自weather API的错误消息。仅当没有存储任何内容时,缓存才会返回false-因此,您应该检查天气API的响应,如果响应有效,则将其存储。
史蒂芬·哈里斯

@StephenHarris:啊哈,我明白了您的意思。我刚开始使用PHP,我只是忽略了所有内容,甚至没有仔细看过代码:)
Umesh Awasthi 2012年

Answers:


11

捕获天气API远程数据

msg,你在你的问题出基本上是从天气API的结果。它说,没有数据可用于您的位置。

您要做的第一件事是对Codex和“ WP HTTP API”进行一些研究。

正确/ WP方式来获取远程数据

在了解了WP HTTP API之后,您将看到执行此操作的常用方法是(简化如下):

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

然后是时候获取适当的数据了。如果远端的所有问题都解决了,它将显示200OK重要信息:远程数据将遵循其内部标准。因此可能会有错误,但是您仍然会200/OK从错误中得到肯定的信息。

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

得到结果

最后是时候检查结果了。首先,我们摆脱了前导/后缀空白。在以下示例中,您将看到如何使用WP HTTP API检查标头。如果捕获了JSON,则继续使用json_decode(),如果得到XML,则使用PHP的本机SimpleXML类。

// 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,则搜索其他服务会更容易。

用瞬态缓存数据

瞬态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' );

有一件很有趣的事情,在检查适当的核心文件时您会发现:核心还为本地请求提供了一个过滤器。但是不要被这个迷住了。仅当您A)从WP安装中提供远程服务并且B)自己使用该服务时,才使用此过滤器!我知道,这可能是#WTF?!一会儿,这并不是您可以在本地安装和生产环境/服务器之间使用不同的SSL验证设置的切换,但是它背后还有一个想法:测试您所使用的服务提供我自己,就像我在此处向WP G +社区解释的那样

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

调试请求及其结果

无需深入了解更新过程,但是WP HTTP API使用WP_HTTP类。它还提供了一个好东西:调试钩子。

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

在哪里$response还可以是一个WP_Error可以告诉您更多信息的对象。

注意:从简短的测试来看,如果将过滤器放置在离实际执行请求的位置较近的位置,则该过滤器似乎仅(出于某种原因)起作用。因此,也许您需要在以下过滤器之一的回调中调用它。

是没有卷曲?

简单。上面显示的“ WP HTTP API”的所有功能基本上都是WP_HTTP类内部的基于函数的包装器,该包装器充当基类(并将在不同的情况下进行扩展)。延伸WP_HTTP_*FsockopenStreamsCurlProxyCookieEncoding。如果将回调链接到'http_api_debug'-action,则第三个参数将告诉您哪个类用于您的请求。您不必直接调用类。只需使用功能。

对于大多数远程/ HTTP API请求,它是WP_HTTP_curl类,它是PHP本机curl库的包装。

WP_HTTP_curl类内部,您将找到request()方法。此方法提供了两个过滤器来拦截SSL行为:一个用于本地请求'https_local_ssl_verify',一个用于远程请求'https_ssl_verify'。WP可能会定义locallocalhost,你会得到什么returnget_option( 'siteurl' );


注意:此答案可以理解为我给出的答案的扩展。
kaiser 2012年

感谢您的输入,我不确定waether API的响应,因为只有当我们没有数据时才会调用它,我检查了API的URL并返回了我的有效数据。将尝试对其进行更多调试
Umesh Awasthi 2012年

@UmeshAwasthi请尝试我上面写的内容-逐步进行。首先查看您从wp_remote_request()URL获得的信息,然后进一步回答。这是一个非常完整的教程,向您展示了在WP中发出HTTP请求的正确方法。进一步说明:WP_HTTP_curl使用上面显示的功能时,您不必调用类,因为WordPress已经为您做到了。
kaiser 2012年

我正在测试它。一旦完成,它就会更新:)
Umesh Awasthi 2012年

1
虽然问题是其他问题,但是我将您的回答标记为已接受,因为它提供了更好的方法来完成相同的工作,我认为,如果平台提供了一些API,则更好地使用它们,谢谢!
Umesh Awasthi,2012年

3

问题不在于“瞬态”功能。这看起来像是您的第三方API返回的错误消息。使用前,您可能需要检查一下set_transientset_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)statement.I不知道的WP_HTTP_curl类将尝试使用
Umesh制作Awasthi

@UmeshAwasthi,这个条件没有什么奇怪的。如果您在瞬态缓存中有当前数据,则不想从API中检索它。只有当您的瞬态缓存已过期时,您才能提取新信息。
s_ha_dum 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.