REST APIs 基础

尽管 REST API 没有正式的标准,但大多数开发人员都同意使用相同的基础。这种技术使用的通信协议 HTTP 确实有一个标准,这一点很有帮助。在本节中,我们将尝试描述 REST API 应如何工作。

HTTP 请求方法

在第 2 章 "使用 PHP 的 Web 应用程序" 中,我们已经介绍了 HTTP 方法的概念。我们解释说,HTTP 方法只是请求的动词,它定义了请求要执行的操作。在使用 HTML 表单时,我们已经定义了这种方法:表单标签可以获得一个可选属性 method,它将使表单以特定的 HTTP 方法提交。

使用 REST API 时,您不会使用表单,但您仍然可以指定请求的方法。事实上,两个请求可以使用相同的参数、标头等发送到同一端点,但由于其方法而具有完全不同的行为,这使得它们成为请求中非常重要的一部分。

由于我们非常重视 HTTP 方法来识别请求试图执行的操作,因此我们很自然地需要其中一些方法。 到目前为止,我们已经介绍了 GET 和 POST,但实际上有八种不同的方法:GET、POST、PUT、DELETE、OPTIONS、HEAD、TRACE 和 CONNECT。您通常只会与其中四个人一起工作。让我们详细看看它们。

GET

当请求使用 GET 方法时,意味着它正在请求有关给定实体的信息。端点应该包含该实体的信息,例如一本书的 ID。GET 还可用于查询对象列表,可以是所有对象、已过滤对象或已分页对象。

GET 请求可以在需要时向请求添加额外的信息。例如,如果我们尝试检索包含字符串“rings” 的所有书籍,或者如果我们想要完整书籍列表的页码 2。 如您所知,这些额外信息将作为 GET 参数添加到查询字符串中,该参数是由与号 (&) 连接的键值对列表。 因此,这意味着对 http://bookstore.com/books?year=2001&page3 的请求可能用于获取 2001 年出版的图书列表的第二页。

REST API 拥有有关可用端点和参数的大量文档,因此您应该很容易学会正确查询。 尽管如此,即使它将被记录下来,您也应该期望参数具有直观的名称,如示例中的名称。

POST 和 PUT

POST 是您已经了解的第二种 HTTP 方法。 您在表单中使用它的目的是“发布”数据,即尝试更新服务器端的资源。 当您想要添加或更新一本新书时,您发送了一个 POST 请求,并将该书的数据作为 POST 参数。

POST 参数以类似于 GET 参数的格式发送,但它们不是作为查询字符串的一部分,而是作为请求正文的一部分包含在内。 HTML 中的表单已经为您做到了这一点,但是当您需要与 REST API 通信时,您应该知道如何自己执行此操作。 在下一节中,我们将向您展示如何使用表单以外的工具执行 POST。 另请注意,您可以将任何数据添加到请求正文中; 在正文中发送 JSON 而不是 POST 参数是很常见的。

PUT 方法与 POST 方法十分相似。它也试图在服务器端添加或更新数据,为此,它还在请求的正文中添加了额外的信息。为什么我们要使用两种不同的方法来做同样的事情呢?实际上,这些方法有两个主要区别:

  • PUT 请求要么创建资源,要么更新资源,但受影响的资源是端点定义的资源,而不是其他资源。这意味着,如果我们要更新一本书,端点应说明该资源是一本书,并指定它,例如 http://bookstore.com/books/8734 。另一方面,如果在端点中没有确定要创建或更新的资源,或同时影响其他资源,则应使用 POST 请求。

  • idempotent 这个词很复杂,但概念却很简单。惰性 HTTP 方法是一种可以被多次调用,且结果始终相同的方法。例如,如果您想将一本书的标题更新为 "堂吉诃德",那么无论您调用多少次,结果都是一样的:资源的标题将是 "堂吉诃德"。另一方面,非幂等方法在执行相同请求时可能会返回不同的结果。例如,一个端点可以增加某本书的库存。每次调用时,库存都会越来越多,因此结果也不一样。PUT 请求是幂等的,而 POST 请求则不是。

即使考虑到这一解释,误用 POST 和 PUT 也是开发人员经常犯的错误,尤其是当他们缺乏足够的 REST API 开发经验时。由于 HTML 表单只能用 POST 而不是 PUT 发送数据,因此前者更受欢迎。你可能会发现在 REST API 中,所有更新数据的端点都是 POST,尽管其中一些端点应该是 PUT。

DELETE

DELETE HTTP 方法不言自明。它用于删除服务器上的资源。与 PUT 请求一样,DELETE 端点应确定要删除的特定资源。例如,我们想从数据库中删除一本书。我们可以向类似 http://bookstore.com/books/23942 的端点发送 DELETE 请求。

DELETE 请求只是删除资源,它们已经由 URL 确定。不过,如果你需要向服务器发送额外信息,你可以使用请求的正文,就像使用 POST 或 PUT 一样。事实上,你总是可以在请求正文中发送信息,包括 GET 请求,但这并不意味着这样做是一种好的做法。

响应状态码

如果说 HTTP 方法对请求非常重要,那么状态代码对响应几乎是不可或缺的。只需一个数字,客户端就能知道请求发生了什么。当你知道状态代码是一种标准,并且它们在互联网上有大量的文档时,这一点就特别有用了。

在第 2 章 "使用 PHP 的 Web 应用程序" 中,我们已经介绍了最重要的状态代码,下面我们再次列出它们,并增加一些对 REST API 非常重要的状态代码。有关状态代码的完整列表,请访问 https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

2xx – success

所有以 2 开头的状态代码都用于成功处理请求的响应,无论请求是 GET 还是 POST。这类状态代码中最常用的有以下几种:

  • 200 OK:这是通用的 "一切正常" 响应。如果您正在请求资源,您将在响应正文中获得该资源;如果您正在更新资源,这将意味着新数据已成功保存。

  • 201 created:这是使用 POST 或 PUT 成功创建资源时使用的响应。

  • 202 accepted:该响应表示请求已被接受,但尚未处理。当客户端需要对非常繁重的操作作出直接响应时,这种响应可能会很有用:服务器发送已接受的响应,然后开始处理。

3xx – redirection

尽管您可能认为只有一种类型的重定向,但仍有一些改进:

  • 301 moved permanently:这表示资源已被移动到不同的 URL,因此从那时起,您应尝试通过响应正文中提供的 URL 进行访问。

  • 303 see other:这表示请求已被处理,但要查看响应,您需要访问响应正文中提供的 URL。

4xx – client error

此类别的状态代码描述了由于客户请求而出现的错误:

  • 400 bad request:这是对错误请求的一般响应,即端点语法错误或未提供某些预期参数。

  • 401 unauthorized:这意味着客户端尚未成功通过身份验证,而客户端试图访问的资源需要通过身份验证。

  • 403 forbidden:该错误信息表示,即使客户端已通过身份验证,它也没有足够的权限访问该资源。

  • 404 not found:未找到特定资源。

  • 405 method not allowed:例如,我们试图使用 PUT,但端点只接受 POST 请求。

5xx – server error

服务器端有多达 11 种不同的错误,但我们只对其中一种感兴趣:500 内部服务器错误。当处理请求时出现意外情况(如数据库错误)时,可以使用此状态代码。

REST API 安全

REST API 是一种强大的工具,因为它允许开发人员从服务器检索和/或更新数据。但是,能力越大,责任越大,在设计 REST API 时,您应该考虑尽可能确保数据安全。想象一下,任何人都可以通过简单的 HTTP 请求代表你发布推文!

与使用网络应用类似,这里有两个概念:验证和授权。身份验证是指识别某人的身份,即把他或她的请求与数据库中的用户联系起来。另一方面,授权是允许特定用户执行某些操作。可以把身份验证看作是用户登录,而授权则是给予权限。

REST API 需要非常小心地管理这两个概念。开发人员通过身份验证并不意味着他可以访问服务器上的所有数据。有时,用户只能访问自己的数据,而有时,您希望实施一个角色系统,其中每个角色都有不同的访问级别。这始终取决于你正在构建的应用程序的类型。

虽然授权发生在服务器端,即由服务器的数据库决定某个用户是否可以访问某个资源,但身份验证必须由客户端触发。这意味着客户端必须知道 REST API 使用的认证系统,才能进行认证。每个 REST API 都会实现自己的身份验证系统,但也有一些众所周知的实现方式。

基本访问认证

基本访问身份验证(Basic access authentication,简称 BA),顾名思义,就是基本的。客户端在每次请求的头部添加用户信息,即用户名和密码。问题是,这些信息只是用 BASE64 编码,并没有加密,因此入侵者很容易就能破译报头,获取纯文本密码。如果您必须使用这种方法,老实说,这是一种非常简单的身份验证方法,我们建议您在使用 HTTPS 时使用这种方法。

要使用这种方法,您需要将用户名和密码连接起来,如 username:password,使用 Base64 对生成的字符串进行编码,然后添加授权标头如下:

Authorization: Basic <encoded-string>

OAuth 2.0

如果说基本身份验证非常简单而且不安全,那么 OAuth 2.0 就是 REST API 用来进行身份验证的最安全的系统,之前的 OAuth 1.0 也是如此。该标准实际上有不同的版本,但都基于相同的基础:

  1. 没有用户名和密码。相反,REST API 的提供者会向开发者分配一对凭证—​令牌和密文。

  2. 为了进行身份验证,开发人员需要向 "令牌" 端点发送 POST 请求。该请求必须包含编码后的开发人员凭证。

  3. 服务器用会话令牌回复前一个请求。你向 REST API 提出的每个请求都必须包含这个(而不是第一步中提到的凭据)。出于安全原因,会话令牌会过期,因此过期时必须再次重复第二步。

尽管该标准出台不久(2012 年以后),但一些大公司(如 Google 或 Facebook)已经在其 REST API 中实施了该标准。它可能看起来有点过于复杂,但你很快就会使用它,甚至实现它。