HTTP API

介绍

HTTP代表超文本传输协议,是整个互联网的基础通信协议。即使这是您第一次使用HTTP,您可能也理解得比您意识到的要多。在最基本的层面上,HTTP的工作原理如下:

  • “您好,XYZ服务器,请给我abc.html文件好吗?”
  • “你好,小客户,是的,你可以,给你”

在PHP中有许多不同的方法来发送HTTP请求。WordPress HTTP API的目的是支持尽可能多的方法,并使用最适合特定请求的方法。

WordPress HTTP API还可以用于与其他API(如Twitter API或Google Maps API)进行通信和交互。

 

HTTP方法

HTTP有几种方法或动词来描述特定类型的动作。尽管还有一些功能,WordPress为三种最常见的功能提供了预构建功能。无论何时发出HTTP请求,都会传递一个方法,以帮助服务器确定客户端请求的操作类型。

 

GET

GET用于检索数据。这是迄今为止最常用的动词。每次查看网站或从API中提取数据时,都会看到GET请求的结果。事实上,你的浏览器向你正在阅读这篇文章的服务器发送了一个GET请求,并要求提供用于构建这篇文章的数据。

 

POST

POST用于将数据发送到服务器,以便服务器以某种方式进行操作。例如,联系人表单。当您在表单字段中输入数据并单击“提交”按钮时,浏览器会获取数据并将POST请求与您在表单中输入的文本一起发送到服务器。服务器将从那里处理联系人请求。

 

HEAD的知名度远不如其他两个。HEAD本质上与GET请求相同,只是它不检索数据,只检索有关数据的信息。这些数据描述了数据上次更新的时间、客户端是否应缓存数据、数据类型等。现代浏览器通常会向您以前访问过的页面发送HEAD请求,以确定是否有任何更新。如果没有,您可能实际上看到的是以前下载的页面副本,而不是不必要地使用带宽拉入同一副本。

所有好的API客户端在执行GET请求之前都会使用HEAD,以潜在地节省带宽。虽然如果HEAD说有新数据,则需要两个单独的HTTP请求,但GET请求的数据量可能非常大。只有在HEAD说数据是新的或不应该缓存时才使用GET,这将有助于节省昂贵的带宽和加载时间。

 

自定义方法

还有其他HTTP方法,例如PUT、DELETE、TRACE和CONNECT。本文将不讨论这些方法,因为在WordPress中没有预构建的方法来使用它们,API实现它们也不常见。

根据服务器的配置方式,您还可以实现自己的其他HTTP方法。跳出标准方法始终是一场冒险,并对其他开发人员创建客户端以使用您的站点或API施加了巨大的潜在限制,然而,您可以使用WordPress的任何方法。在本文中,我们将简要介绍如何做到这一点。

 

响应(Response)代码

HTTP同时利用数字和字符串响应代码。以下是标准响应代码,而不是对每种代码进行冗长的解释。您可以在创建API时定义自己的响应代码,但是,除非您需要支持特定类型的响应,否则最好坚持使用标准代码。自定义代码通常在1xx范围内。

 

代码分类

响应类型可以通过三位代码中最左边的数字快速看到。

状态码 描述
2xx 请求成功
3xx 请求被重定向到另一个URL
4xx 由于客户端错误,请求失败。通常是无效的认证或丢失数据
5xx 请求因服务器错误而失败。常见的是丢失或配置错误的配置文件

常见代码

这些是您将遇到的最常见的代码。

状态码 描述
200 OK - 请求成功
301 资源被永久地移动了
302 资源被暂时移动
403 禁止 - 通常是由于无效的认证
404 没有找到资源
500 内部服务器错误
503 服务不可用

 

从API获取数据

GitHub提供了一个优秀的API,在很多公共方面不需要应用注册,因此为了演示其中一些方法,示例将针对GitHub API。

在WordPress中,通过wp_remote_get()函数获取数据非常简单。此函数有以下两个参数:

  1. $url – 从中检索数据的资源,必须是标准HTTP格式
  2. $args – 可选 – 您可以在这里传递一个参数数组来改变行为和header,例如cookie、遵循重定向等。

假设以下默认值,但可以通过$args参数进行更改:

  • method – GET
  • timeout – 5 – 放弃前等待多长时间
  • redirection – 5 – 遵循重定向的次数
  • httpversion – 1.0
  • blocking – true – 页面的其余部分是否应等待完成加载,直到此操作完成?
  • headers – array()
  • body – null
  • cookies – array()

让我们使用GitHub用户帐户的URL,看看可以获得什么样的信息

$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );

$response 将包含关于我们的请求的所有header、内容和其他元数据

Array(
	[headers] => Array(
		[server] => nginx
		[date] => Fri, 05 Oct 2012 04:43:50 GMT
		[content-type] => application/json; charset=utf-8
		[connection] => close
		[status] => 200 OK
		[vary] => Accept
		[x-ratelimit-remaining] => 4988
		[content-length] => 594
		[last-modified] => Fri, 05 Oct 2012 04:39:58 GMT
		[etag] => "5d5e6f7a09462d6a2b473fb616a26d2a"
		[x-github-media-type] => github.beta
		[cache-control] => public, s-maxage=60, max-age=60
		[x-content-type-options] => nosniff
		[x-ratelimit-limit] => 5000
	)

	[body] => {"type":"User","login":"blobaugh","gravatar_id":"f25f324a47a1efdf7a745e0b2e3c878f","public_gists":1,"followers":22,"created_at":"2011-05-23T21:38:50Z","public_repos":31,"email":"ben@lobaugh.net","hireable":true,"blog":"http://ben.lobaugh.net","bio":null,"following":30,"name":"Ben Lobaugh","company":null,"avatar_url":"https://secure.gravatar.com/avatar/f25f324a47a1efdf7a745e0b2e3c878f?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png","id":806179,"html_url":"https://github.com/blobaugh","location":null,"url":"https://api.github.com/users/blobaugh"}
	[response] => Array(
		[preserved_text 5237511b45884ac6db1ff9d7e407f225 /] => 200
		[message] => OK
	)

	[cookies] => Array()
	[filename] =>
)

 

获取你想要的body

只需使用wp_remote_retrieve_body()检索body。该函数只接受一个参数,即来自任何其他 wp_remote_X 函数的响应,其中retrieve不是下一个值。

$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
$body     = wp_remote_retrieve_body( $response );

仍然使用上一个示例中的GitHub资源,$body将得到

{"type":"User","login":"blobaugh","public_repos":31,"gravatar_id":"f25f324a47a1efdf7a745e0b2e3c878f","followers":22,"avatar_url":"https://secure.gravatar.com/avatar/f25f324a47a1efdf7a745e0b2e3c878f?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png","public_gists":1,"created_at":"2011-05-23T21:38:50Z","email":"ben@lobaugh.net","following":30,"name":"Ben Lobaugh","company":null,"hireable":true,"id":806179,"html_url":"https://github.com/blobaugh","blog":"http://ben.lobaugh.net","location":null,"bio":null,"url":"https://api.github.com/users/blobaugh"}

如果除了获取body之外,没有任何其他操作要对响应执行,那么可以使用

$body = wp_remote_retrieve_body( wp_remote_get( 'https://api.github.com/users/blobaugh' ) );

许多辅助函数可以在一行代码上类似地使用。

 

获取响应代码

您可能需要检查响应代码以确保检索成功。这可以通过wp_remote_retrieve_response_code()函数完成:

$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
$http_code = wp_remote_retrieve_response_code( $response );

如果成功,$http_code将包含200

 

获取特定header

如果您希望检索特定的header,比如最后修改时间,那么可以使用wp_remote_retrieve_header()。此函数采用两个参数

  1. $response – GET调用的响应
  2. $header – 要检索的header的名称

检索上次修改的header

$response      = wp_remote_get( 'https://api.github.com/users/blobaugh' );
$last_modified = wp_remote_retrieve_header( $response, 'last-modified' );

$last_modified将包含[last-modified] => Fri, 05 Oct 2012 04:39:58 GMT
您还可以使用wp_remote_retrieve_headers( $response )检索数组中的所有header。

 

使用基本身份验证的GET

安全的API提供了多种不同类型的身份验证中的一种或多种。一种常见但安全性不高的身份验证方法是HTTP基本身份验证。它可以通过将“Authorization”传递给wp_remote_get()函数的第二个参数以及其他HTTP方法函数在WordPress中使用。

$args = array(
    'headers' => array(
        'Authorization' => 'Basic ' . base64_encode( YOUR_USERNAME . ':' . YOUR_PASSWORD )
    )
);
wp_remote_get( $url, $args );

 

将数据POST到API

相同的辅助方法(wp_remote_retrieve_body()等)可用于所有HTTP方法调用,并以相同的方式使用。

POST数据使用wp_remote_post()函数完成,并采用与wp_remote_get()完全相同的参数。这里需要注意的是,您需要为第二个参数传入数组中的所有元素。Codex提供了默认的可接受值。您现在只需要关心正在发送的数据,其他值将被默认。

要将数据发送到服务器,您需要构建一个关联数据数组。该数据将被分配到'body'值。从服务器端来看,值将如您所期望的那样出现在$_POST变量中。例如,如果body => array( 'myvar' => 5 ),那么在服务器上就是$_POST['myvar'] = 5

由于GitHub不允许POST到上一个示例中使用的API,因此本示例将假设它允许。通常,如果您想将数据POST到API,您需要联系API的维护人员,并获取API密钥或其他形式的身份验证令牌。这仅仅证明了您的应用程序可以像用户登录网站一样操作API上的数据。

假设我们正在提交一份包含以下字段的联系表单:姓名、电子邮件、主题、评论。要设置body,我们需要执行以下操作:

$body = array(
	'name'    => 'Jane Smith',
	'email'   => 'some@email.com',
	'subject' => 'Checkout this API stuff',
	'comment' => 'I just read a great tutorial. You gotta check it out!',
);

现在我们需要设置将传递给wp_remote_post()的第二个参数的其余值

$args = array(
	'body'        => $body,
	'timeout'     => '5',
	'redirection' => '5',
	'httpversion' => '1.0',
	'blocking'    => true,
	'headers'     => array(),
	'cookies'     => array(),
);

那么当然要调用了

$response = wp_remote_post( 'http://your-contact-form.com', $args );

 

HEAD减少带宽使用

在检索资源之前,使用HEAD检查资源状态可能非常重要,有时API会要求这样做。在高流量API上,GET通常限制为每分钟或每小时的请求数。甚至不需要尝试GET请求,除非HEAD请求显示API上的数据已更新。

如前所述,HEAD包含有关数据是否已更新、是否应缓存数据、缓存副本何时过期以及有时对API请求的速率限制的数据。

回到GitHub示例,这里有几个需要注意的header。这些header中的大多数都是标准的,但您应该始终检查API文档,以确保您了解哪些header被命名为什么,以及它们的用途。

  • x-ratelimit-limit – 一段时间内允许的请求数
  • x-ratelimit-remaining – 时间段内剩余可用请求的数量
  • content-length – 内容的大小(字节),如果内容相当大,可以警告用户
  • last-modified – 上次修改资源的时间,对缓存工具非常有用
  • cache-control – 客户端应该如何处理缓存

以下内容将检查我的GitHub用户帐户的HEAD值:

$response = wp_remote_head( 'https://api.github.com/users/blobaugh' );

$response应该类似于

Array(
	[headers] => Array
		(
		[server] => nginx
		[date] => Fri, 05 Oct 2012 05:21:26 GMT
		[content-type] => application/json; charset=utf-8
		[connection] => close
		[status] => 200 OK
		[vary] => Accept
		[x-ratelimit-remaining] => 4982
		[content-length] => 594
		[last-modified] => Fri, 05 Oct 2012 04:39:58 GMT
		[etag] => "5d5e6f7a09462d6a2b473fb616a26d2a"
		[x-github-media-type] => github.beta
		[cache-control] => public, s-maxage=60, max-age=60
		[x-content-type-options] => nosniff
		[x-ratelimit-limit] => 5000
	)
    [body] =>
    [response] => Array
		(
		[preserved_text 39a8515bd2dce2aa06ee8a2a6656b1de /] => 200
		[message] => OK
	)
    [cookies] => Array(
	)
	[filename] =>
)

与前两个函数一样,可以在此函数上使用所有相同的辅助函数。这里的例外是HEAD永远不会返回body,所以元素总是空的。

 

任意请求方法

如果需要使用上述任何函数都不支持的HTTP方法发出请求,请不要死机。WordPress杰出的开发人员已经想到了这一点,并热情地提供了wp_remote_request()。该函数采用与wp_remote_get()相同的两个参数,并允许您指定HTTP方法。您需要传递什么数据取决于您的方法。

要发送DELETE方法示例,您可能需要类似以下内容:

$args     = array(
	'method' => 'DELETE',
);
$response = wp_remote_request( 'http://some-api.com/object/to/delete', $args );

 

缓存简介

缓存是一种做法,将常用对象或需要大量时间构建的对象保存到快速对象存储中,以便在以后的请求中快速检索。这可以避免再次花费时间获取和构建对象。缓存是一个庞大的主题,它是网站优化的一部分,可以单独包含在整个系列的文章中。接下来的内容只是对缓存的介绍,以及为API响应快速设置缓存的简单而有效的方法。

为什么要缓存API响应?嗯,一个很关键的原因是外部API拖慢了你的网站。许多顾问会告诉你,利用外部API可以减少连接量和处理量,以及昂贵的带宽,从而提高网站的性能,但有时情况并非如此。

在服务器发送数据的速度和远程服务器处理请求、生成数据并将其发回所需的时间之间,这是一种很好的平衡。第二个引人注目的方面是,许多API在一个时间段内的请求数量有限,并且可能限制应用程序一次连接的数量。缓存通过将数据的副本放置在服务器上,直到需要刷新为止,从而帮助解决这些难题。

 

你应该什么时候缓存

简单的答案是“总是”,但也有一些时候你不应该这样做。如果您正在处理实时数据,或者API在header中特别指出不要缓存,您可能不想缓存,但对于所有其他情况,通常最好缓存从API检索的任何资源。

 

WordPress Transients(瞬态)

WordPress瞬态提供了一种存储和使用缓存对象的方便方法。瞬态存在一段指定的时间,或者直到您需要它们在API中的资源更新后过期。在WordPress中使用瞬态功能可能是您遇到过的最容易使用的缓存系统。仅三个函数就可以帮助你完成所有繁重的工作。

 

缓存对象(设置瞬态)

缓存对象是通过set_transient()函数完成的。此函数采用以下三个参数:

  1. $transient – 瞬态名称,供之后参考
  2. $value – 瞬态值
  3. $expiration – 从保存瞬态到其过期的时间是多少秒

将上面的GitHub用户信息响应缓存一小时的示例如下:

$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );

set_transient( 'prefix_github_userinfo', $response, 60 * 60 );

 

获取缓存对象(获取瞬态)

获取缓存对象比设置瞬态要复杂得多。您需要请求瞬态,但还需要检查瞬态是否已过期,如果已过期,请获取更新的数据。通常,set_transient()调用在get_transient()调用内部进行。以下是获取GitHub用户信息的瞬态数据的示例:

$github_userinfo = get_transient( 'prefix_github_userinfo' );

if ( false === $github_userinfo ) {
	// Transient expired, refresh the data
	$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
	set_transient( 'prefix_github_userinfo', $response, HOUR_IN_SECONDS );
}
// Use $github_userinfo as you will

 

删除缓存对象(删除瞬态)

删除缓存对象是所有瞬态函数中最简单的一个,只需向其传递瞬态名称的参数,您就完成了。

要删除Github用户信息:

delete_transient( 'blobaugh_github_userinfo' );

有关瞬态的更多信息,请参见此处