# 一、关于 REST

我们可以将表征状态转移(REST)定义为基于一系列原则的架构风格。REST 在过去几年的兴起与大多数网络应用程序提供的扩展其功能的应用编程接口设计有关。即使它没有绑定到 HTTP，REST 通常也与 web 应用程序相关联。HTTP 恰好很符合 REST 原则。

REST 的原则是统一接口、无状态、可缓存、客户机-服务器、分层系统和按需编码。

这是对 REST 架构的简短介绍。我们需要了解的是 REST 应用程序的基本原理和概貌。通过 HTTP 进行 REST 的想法是尽可能多地使用协议的功能，这样我们就不必重新发明轮子。

在接下来的章节中，我们将看到 ASP.NET 网络应用编程接口如何帮助构建符合 REST 约束的网络应用程序。

## 统一界面

REST 的中心是资源，也就是我们想要使用 API 管理的“东西”。一个资源可以是一篇博客文章、一个客户、一个文档，一般来说，可以是我们想要公开的任何东西。资源有标识符，就像数据库中的记录有主键一样。同样，资源也有一个 URI 来标识它自己。URI 并不代表可以采用不同格式的资源。它只是一个标识符，我们可以用来访问资源。

我们可以向 URI 请求资源，我们获得的是以特定格式表示所请求的资源。该格式在客户端和服务器之间协商，可以是从最常用的`XML`和`JSON`到`HTML`、`PNG`、`CSV`或其他二进制格式。有了资源的表示，客户机可以操纵状态，并使用服务器操作资源(如果它有这样做的权限的话)。

## 无国籍

无国籍状态是 REST 应用程序的基本原则；服务器永远不应该存储关于客户端的信息。这意味着当请求到达服务器时，服务器从存储(通常是数据库)加载资源，并将表示发送回客户端。这是资源的状态。如果一秒钟后，存储上的状态因为新的请求到达而改变，客户端不需要知道。

无状态还意味着服务器永远不应该使用会话或其他机制来存储客户端信息，并且每个请求都不会与过去或未来的请求相关联。

## 可纪念

客户端可以缓存资源，服务器应该提供关于资源本身的可缓存性的信息。如果我们正确管理缓存，我们可以节省到服务器的几次旅行。

## 客户端-服务器

客户看到的是 URI 和资源的表示，仅此而已。客户看不到(当然也没兴趣看到)资源存储在哪里。另一方面，服务器不应该知道客户端是否有特定的资源，如果接口没有改变，服务器和客户端的内部可能会改变，而不会破坏任何东西。

## 分层系统

客户端对服务器知之甚少；例如，它不知道它是否直接连接到服务器，或者它是否通过代理或其他中间服务器(平衡器等)到达服务器。).

## 按需编码

服务器可以通过传递可执行代码来扩展客户端的功能。例如，服务器可以向客户端发送 JavaScript，这样它就可以对数据进行某种类型的操作。

如果我们仔细阅读这些原则，我们会注意到它们的主要焦点是可伸缩性。服务器不应该存储客户端信息的事实允许它节省内存。分层系统允许我们使用缓存服务器作为负载平衡器来获得可扩展性。在遵循客户机-服务器原则的同时添加新的服务器允许我们在客户机不知情的情况下更改实现(例如，从 SQL 数据库到 NoSQL 存储)。

但是我们如何获得它，它是如何工作的呢？在概述 REST 的原始论文中，罗伊·菲尔丁没有将 REST 体系结构与 HTTP 联系起来，但是如前所述，HTTP 似乎非常适合构建 REST 应用编程接口，因为 REST 状态的大部分内容已经在协议本身中构建好了(例如，可缓存性)。

web 本身就是 REST:我们有 URL，它是我们需要的页面的标识符，我们在浏览器中键入 URL 以获得 HTML 格式的表示，我们使用链接将状态转移到另一个页面。

REST 与 SOAP (RPC)的一个不同之处在于，对资源的操作基于与 URI 结合使用的 HTTP 动词。

HTTP 有动词的概念。我们习惯于`GET`和`POST`，因为浏览器管理这两个动词，但是其他的是在 HTTP 规范(RFC 2616)中指定的，可以用于其他操作。

动词的完整列表为:`OPTIONS`、`GET`、`HEAD`、`POST`、`PUT`、`PATCH`、`DELETE`、`TRACE`和`CONNECT`。

这些可以和它们的语义一起使用，所以当我们需要读取一个资源时，我们可以使用`GET`方法，当我们需要删除一个资源时，我们可以使用一个`DELETE`等等。

表 1: HTTP 动词和含义

| 动词 | 上呼吸道感染 | 描述 |
| 得到 | /员额 | 获取帖子列表。 |
| 得到 | /员额/42 | 找一个帖子(id 为 42 的)。 |
| 删除 | /员额/42 | 删除帖子 42。 |
| 邮政 | /员额 | 创建帖子。 |
| 放 | /员额/42 | 更新帖子。 |
| 修补 | /post/42 | 部分更新。 |
| 选择 | /post/42 | 检索资源上的可用操作。 |
| 头 | /post/42 | 只返回 HTTP 头。 |

如上表所示，通过使用正确的 URI 和正确的动词，我们可以使用 CRUD(创建、读取、更新、删除)操作。

向服务器发出请求后，服务器解析请求并构建响应，以将数据或结果返回给客户端。每个响应都用一个状态来表示，HTTP 状态应该在语义上用来通知客户端结果。

有五种类型的 HTTP 状态代码:

*   信息(1xx)
*   成功(2xx)
*   重定向(3xx)
*   客户端错误(4xx)
*   服务器错误(5xx)

每个小组都有自己的细节。例如，如果请求顺利，响应的状态代码在`GET`请求之后是`200 OK`，但是在`POST`请求之后是`201 CREATED`。

在客户未被授权发出请求的情况下，应使用`403 Forbidden`；如果找不到资源，则使用`404 Not found`。

所以，一般情况是找到最能代表当前情况的 HTTP 状态。状态代码的完整列表可以在本书末尾的[附录 A](13.html#sigil_toc_id_78) 中找到。

## GET

`GET`操作用于读取资源。URI 指定了我们正在阅读的资源，我们可以使用`Accept`头来请求特定的格式。例如，考虑这个 HTTP 请求:

```cs
    GET /posts HTTP/1.1
    Accept: application/json

```

`GET`请求指示服务器以`JSON`格式返回“帖子”资源的内容。

```cs
    GET /posts/42 HTTP/1.1
    Accept: text/xml

```

这个`GET`请求要求服务器以`XML`格式返回一个标识符为 42 的`Post`资源。

`GET`操作被认为是安全的，所以它永远不应该修改资源的状态。

如果一切顺利，服务器通常以 HTTP 状态`200 OK`响应`GET`请求，如果 URI 指向不存在的资源，则响应`404 Not found`，如果请求格式不正确，则响应`400 Bad request`。

## 邮政

当`POST`用于创建资源时，资源数据作为请求主体的一部分被发送到服务器。如果一切顺利，服务器会以状态`201 CREATED`进行响应。创建新资源时，最佳做法是在响应中使用`Location`头来指定新创建资源的 URI。这符合 HATEOAS 原则。

* * *

HATEOAS(超媒体作为应用状态的引擎)

在 REST 应用程序中，客户端需要知道尽可能少的信息才能使用该应用程序。理想情况下，客户唯一需要知道的是进入点的 URI。所有其他 URIs 应该由服务器使用位置头或其他机制(例如，rel 链接)来提供，以通知客户端其他资源在哪里。这样，客户机和服务器就不会捆绑在一起，服务器可以在不破坏客户机的情况下更改资源的位置。这是精心设计的 REST API 的基础。

* * *

## PUT

`PUT`用于修改资源。URI 指定了我们要修改的资源，并且正文包含新的资源值。如果响应不包含修改后的资源，则响应 HTTP 状态代码应为`200 OK`或`204 No content`。不需要在`Location`头中返回资源本身的 URI，因为客户端已经知道了。`PUT`必须是幂等的，这意味着成功请求的结果与执行的次数无关。必须能够向服务器发出两个相等的调用，并且服务器不应该返回错误；第二次调用只是重做更新，即使它没有改变资源。

## 删除

`DELETE`用于删除资源。如果响应不包含身体，结果可能是`200 OK`或`204 NO CONTENT`。如果 URI 不正确，找不到资源，可能是`404 Not Found`。

## 总结

这只是对 REST 的简短介绍，正是我们正确使用 ASP.NET Web API 所需要的。REST 是一个很大的话题，已经有整本书都是关于它的。我们刚刚研究了一些原则以及如何使用 HTTP 动词来处理资源。