HTTP 是超文本传输协议,是整个互联网的基础

  • 你好服务器 X,请问有文件 index.html 吗?
  • 你好,我有这个文件,现在发给你。

我们有很多方法可以在 PHP 中发送 HTTP 请求,WordPress HTTP API 的目的是支持尽可能多的方法,并在各种情况下使用最合适的方法。WordPress HTTP API 也可用于和其他 API 进行通信和交互。

# 13.1 HTTP 方法

HTTP 有几种描述特定操作的方法或动词。WordPress 帮我们预先建立了三种最常见的功能,每次一个 HTTP 请求时,WordPress 也会传递一个方法来帮助服务器确定客户端正在请求什么样的动作。

GET

GET 方法用于从服务器获取数据,这是迄今为止最常用的方法,我们查看网站或者从 API 获取数据的时候,我们都会使用 GET 请求,事实上,我们在阅读这篇文章的时候,我们使用的浏览器就是在帮我们展示从服务器 GET 到的页面。

POST

POST 请求用于把数据发送到服务器,以便服务器进行某种方式的操作,例如,一个联系表单。我们把数据输入到这个表单并点击了提交按钮,浏览器会把我们输入的数据以 POST 的方法发送给服务器,服务器收到数据后,会进行一些处理。

HEAD

HEAD 请求的使用比上面两个少得多,HEAD 与 GET 请求基本相同,只不过 HEAD 请求只获取关于数据的信息,不获取数据。这些信息描述了数据的最后更新时间,客户端是否应该缓存数据,数据的类型等等。现代浏览器通常会向已经访问过的页面发送 HEAD 请求,以确定是否需要更新。如果不需要,浏览器展示给我们的是缓存在本地的页面副本,而不用浪费宽带获取一个一模一样的页面。

所有优秀的 API 都应该在执行 GET 请求之前先使用 HEAD 请求来尝试节省带宽。虽然在有数据更新的时候,这种处理方式会发送两次 HTTP 请求,但是相对于通过 GET 方法获取有可能很大的重复数据,先使用 GET 请求测试一下还是可以节省很多带宽的。只有在 HEAD 请求表示数据已被更新或者不应该被缓存的情况下直接使用 GET 请求可以节省一次请求的带宽和时间。

自定义方法

除了上面介绍的,还有其他 HTTP 方法,比如 PUT,DELETE,TRACE,和 CONNECT,本文不会涉及到这些方法,因为 WorPress 没有预先构建这些方法,目前为止我们使用的也不多。

根据服务器的配置,我们也可以实现自定义 HTTP 方法,不过使用标准方法之外的自定义方法像是一场赌博,可能会给其他开发者设置一些潜在的限制,因为他们可能会搞不懂我们的自定义方法。虽然如此,我们可以通过 WordPress 来使用任何喜欢的方法,我们将在下面简要的介绍如何实现这一点。

# 13.2 响应码

HTTP 使用数字和字符串形式的响应代码,而不是对每一个响应做一个冗长的解释,这里指的是标准的响应代码。我们也可以在创建 API 的时候定义自己的响应代码,但是除非需要支持特定类型的响应,我们最好遵循标准代码,自定义代码通常在 1xx 范围内。

响应代码类型

响应类型可以通过响应代码最左边的数字看到。

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

通用代码

下面是我们最常遇到的响应代码。

状态码 描述
200 请求成功
301 资源被永久移动
302 资源暂时移动
403 禁止 – 通常由于验证无效
404 资源未找到
500 内部服务器错误
503 暂停服务

# 13.3 从 API 获取数据

WordPress已经不仅仅是一个博客网站程序,而是一个强大的CMS系统。开源、完善的社区、丰富的接口等等优势正将WordPress推向更高更广泛的领域。

WP REST API,为 WordPress 提供对外标准的RESTFul接口,随着RESTFul的畅行和各种前端框架的出现,WP REST API可以让 WordPress 不仅仅存在WEB端,可以让 WordPress 不仅仅履行一个博客功能,而是可以让 WordPress 程序作为后台终端(BackEnd),然后以各种应用的形式实现在各种各样的设备中。

//获取分类api链接:
/wp-json/wp/v2/categories
//获取标签api链接:
/wp-json/wp/v2/tags
//获取页面api链接:
/wp-json/wp/v2/pages
//获取评论api链接:
/wp-json/wp/v2/comments
1
2
3
4
5
6
7
8

获取特色图片

接口默认不包含特色图片,需要在请求的时候设置 _embed=true

/wp-json/wp/v2/posts?_embed=true
1

获取分页

$.ajax({
  url: url,
  type: 'GET',
  dataType: 'json',
  success: function (data, status, request) {
    totalPage = request.getResponseHeader('x-wp-totalpages');
  }
})
1
2
3
4
5
6
7
8

分页参数

任何包含多个资源的 API 响应都支持几个常见的查询参数,以通过响应数据来处理分页:

?page=:指定要返回的结果的页面。 例如/wp/v2/posts?page=2是帖子结果的第二页

?per_page=:指定在一个请求中返回的记录数,指定为1到100之间的整数。 例如,/wp/v2/posts?per_page=1将只返回集合中的第一个帖子

?offset=:指定开始检索帖子的任意偏移量 例如,/wp/v2/posts?offset=6将使用每页的默认帖子数,但从集合中的第6个帖子开始

?per_page=5&page=4相当于?per_page=5&offset=15

提示:大型查询可能会损害网站性能,因此per_page的上限为100条记录。如果您希望检索超过100条记录,例如构建所有可用类别的客户端列表,您可以创建多个API请求并将结果合并到应用程序中。

X-WP-Total:集合中的记录总数 X-WP-TotalPages:包含所有可用记录的总页数

# 文章

  • 1`获取最新文章(默认获取到最新的10篇文章)
/wp-json/wp/v2/posts
1

==

/wp-json/wp/v2/posts?page=1
1

效果相同,page用于指定页数,WP REST API 默认返回10条数据,用page指定数据获取的游标。如

/wp-json/wp/v2/posts?page=2
1

可取回最新的第11条数据到第20条数据,以此类推。

  • 2`设置获取的每页文章数量及分页
/wp-json/wp/v2/posts?per_page=5
1

per_page=5 用于指定返回文章每页的数量,这里指定每页数量为5篇。

?per_page=8&page=1&orderby=date&order=desc
1

这部分就是各种参数,per_page是每页记录数,page是当前第几页,orderby是通过什么方式排序,order 是排序方式。不同的路由终点参数也会有所不同。

filter[posts_per_page]与page联合使用:

/wp-json/wp/v2/posts?filter[posts_per_page]=5&page=2
1
  • 3`获取指定分类的文章
/wp-json/wp/v2/posts?filter[cat]=2
1

filter[cat]=2 指定分类ID为2 ,返回分类ID为2的文章。

  • 4`获取指定标签的文章
/wp-json/wp/v2/posts?/wp-json/wp/v2/posts?filter[tag]=hotnews
1
  • 5`获取指定分类和有指定标签的文章
/wp-json/wp/v2/posts?filter[cat]=2&filter[tag]=library
1
  • 6`获取指定日期的文章
/wp-json/wp/v2/posts?filter[year]=2016&filter[monthnum]=03
1
  • 7`获取指定作者的文章
/wp-json/wp/v2/posts?filter[author_name]=mla
1
  • 8`按关键词搜索文章
/wp-json/wp/v2/posts?search='字符串'
1
  • 9`获取随机文章
/wp-json/wp/v2/posts?filter[orderby]=rand
1
  • 10`获取相关文章

在网站中,在做 SEO 优化和页面内容布局时,获取相关文章是比较常见的,可以通过以上几个条件组合来达到获取相关文章的效果。

按标签获取相关文章:

/wp-json/wp/v2/posts?filter[orderby]=rand&filter[tag]=library&filter[posts_per_page]=6
1

按标签获取相关文章:

/wp-json/wp/v2/posts?filter[orderby]=rand&filter[cat]=2&filter[posts_per_page]=6
1
  • 11`获取指定文章数据
/wp-json/wp/v2/posts/188
1

# 分类和标签

  • 1`获取所有的分类
/wp-json/wp/v2/categories
1
  • 2`获取指定分类ID的分类信息
/wp-json/wp/v2/categories/2
1
  • 3`获取所有的标签
/wp-json/wp/v2/tags
1
  • 4`获取指定标签ID的标签信息
/wp-json/wp/v2/tags/3
1

# 媒体文件

  • 1`获取所有的媒体信息
/wp-json/wp/v2/media
1
  • 2`获取指定媒体ID的媒体信息
/wp-json/wp/v2/media/17
1

# 页面

  • 1`获取所有的页面信息
/wp-json/wp/v2/pages
1
  • 2`获取指定页面ID的页面信息
/wp-json/wp/v2/pages/2
1

# 类型

  • 1`获取当前wordpress所有的内容类型
/wp-json/wp/v2/types
1

一般情况下会返回 post, page 和 attachment 三种类型

  • 2`取指定类型
/wp-json/wp/v2/types/post
1

# 评论

  • 1`获取所有评论信息
/wp-json/wp/v2/comments
1
  • 2`获取指定评论ID的单条评论信息
/wp-json/wp/v2/comments/2
1

# 用户

  • 1`获取所有的用户信息
/wp-json/wp/v2/users
1
  • 2`获取指定用户ID的用户信息
/wp-json/wp/v2/users/2
1

# 13.4 将数据发送到 API

wp_remote_retrieve_body() 可以在所有 HTTP 方法上面以同样的方式使用。

发送数据应该使用 wp_remote_post() 函数完成,该函数的参数和 wp_remote_get() 完全一样,需要注意的是,我们应该把需要发送的所有数据放到第二个参数里面,函数提供了一些基本默认数据,我们只需要关注我们发送的数据即可。

要发送数据到服务器,我们需要建立一个关联数组,该数组将被设置为 ‘body’ 的值,如我们所愿,在接受请求的服务端,这个数组的值将出现在 $_POST 变量中。举个例子,如果 body => array( 'myvar' => 5 ),在接收服务器上就是 $_POST['myvar'] = 5 。

通常,如果需要将数据发布到 API,我们需要从 API 提供方获取 API 密钥或其他形式的身份验证令牌。用来证明我们的应用程序可以像用户一样登录到服务器,通过 API 操作服务器上的数据。

比如我们正在提交一个联系表单,其中包含 name, email, subject, comment 这些字段,我们首先需要设置 POST 请求的 body 信息。

$body = array(
   'name' => 'Jane Smith',
   'email' => 'some@email.com',
   'subject' => 'Checkout this API stuff',
   'comment' => 'I just read a great tutorial by this Ben Lobaugh. It taught me amazing things about interacting with APIs in WordPress! You gotta check it out!'
);
1
2
3
4
5
6

然后,把我们设置的 $body 信息和其他可选的参数设置为 wp_remote_post() 的第二个参数。

$args = array(
   'body' => $body,
   'timeout' => '5',
   'redirection' => '5',
   'httpversion' => '1.0',
   'blocking' => true,
   'headers' => array(),
   'cookies' => array()
);
1
2
3
4
5
6
7
8
9

然后,发送请求。

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

# 13.5 注意带宽使用情况

在获取资源之前,使用 HEAD 检查资源状态可能非常重要(有些 API 要求这样做),在高流量的 API 上,GET 请求通常会被限制频次,除非 HEAD 请求的返回信息显示 API 上的数据已更新,否则不需要发送 GET 请求。

像上面说的一样,HEAD 包含数据是否已经更新,数据是否应该被缓存,缓存何时过期以及有时对 API 的请求速率限制。

# 13.6 发送任何形式的请求

如果我们需要使用和上面介不一样的方法来发送请求,不要怕,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 );
1
2
3
4

# 13.7 缓存

缓存是一种很常见的实践,我们经常会把比较耗时的常用对象保存到一个方便快速获取的缓存库里面,以便在以后的请求中快速获取。这样可以避免服务器耗费不必要的时间重新生成重复数据。缓存是一个比较大的话题,是网站性能优化的一部分,我们在这里不展开讨论。下面的内容只是对缓存的介绍,以及设置 HTTP API 响应缓存的方法。

为什么要缓存 API 响应呢?有时候,外部 API 会降低我们网站的响应速度。我们可能会在某些地方看到,利用外部 API 可以减少连接和处理的数量、以及昂贵的带宽,从而提高网站性能,但在有些情况下,会出现相反的情况。

我们需要在服务器发送数据的速度和请求远程数据并等待其返回所花的时间之间进行平衡。后者显而易见的问题是许多 API 会对一段时间内的请求数量做限制,并且可能会限制一次请求的连接数量。缓存可以把获取到的远程数据副本放到我们自己的服务器上,从而解决这些问题,直到数据需要刷新为止。

应该什么时候进行缓存?

答案是,大多数情况下,我们都应该进行缓存,除非我们需要处理的是实时数据,或者 API 的 HEAD 信息明确指定了不缓存数据。

WordPress 的缓存 API

WordPress 缓存 API 为我们提供了一种方便的方式来存储和使用缓存,缓存有一段时间的有效期,过了有效期或远程 API 中的数据更新了之后,我们需要重新设置缓存,WordPress 的缓存功能可能是最方便使用的缓存系统了,缓存 API 只提供了三个功能来帮助我们完成繁杂的工作。

设置缓存

我们使用 set_transient() 函数来缓存一个对象,该函数接受以下三个参数:

  • $transient – 缓存的名称,供获取和删除缓存使用
  • $value – 缓存的值
  • $expiration – 缓存的到期时间
$response = wp_remote_get( 'https://api.github.com/users/mla' );
set_transient( 'blobaugh_github_userinfo', $response, 60*60 );
1
2

获取缓存

获取缓存对象要比设置缓存复杂一点,在获取缓存之前,我们需要先检查缓存是否已经过期,如果已过期,我们需要从 API 获取新数据,然后重新设置缓存供下一次获取。通常 set_transient() 和 get_transient() 是一起使用的。

$github_userinfo = get_transient( 'mla_github_userinfo' );

if( false === $github_userinfo ) {
   // 缓存已过期,刷新缓存
   $response = wp_remote_get( 'https://api.github.com/users/mla' );
   set_transient( 'mla_github_userinfo', $response, 60*60 );
}

1
2
3
4
5
6
7
8

删除缓存

删除缓存就容易得多了,只需要把缓存的名称传递给 delete_transient() 函数就可以了。

delete_transient( 'mla_github_userinfo' );
1