REST 的起源?
REST 流行起来是因为 Roy Fielding 在他 2000 年的博士论文 Architectural Styles and the Design of Network-based Software Architectures 中介绍并推荐了它。Roy 因为他对 web 开发,特别是 HTTP 规范的贡献而闻名。
什么是 RESTful APIs ?
REST 即表述性状态转移,是一种用于构建可扩展 web 服务的架构风格。Roy 提倡使用他在 HTTP 标准 中参与制定的请求方法来赋予 HTTP 请求语义。
因此当使用 REST 时,下面的 HTTP 请求都有不同的语义:
GET /object/list
POST /object/list
PUT /object/list
这只是一部分 HTTP 请求方法。完整的列表如下:CONNECT
, DELETE
, GET
, HEAD
, OPTIONS
, PATCH
, POST
, PUT
, TRACE
。可以原谅你从没有听说过其中的某些方法,因为它们中的一部分也一直都没得到客户端或服务端的支持。
Roy 同样主张使用 他参与制定的 HTTP 响应状态码来传达响应的语义。共有 38 种 HTTP 响应状态码。
Method | Method |
---|---|
200 OK | 201 Created |
202 Accepted | 203 Not authorized |
204 No content | 205 Reset content |
206 Partial content | |
300 Multiple choice | 301 Moved permanently |
302 Found | 303 See other |
304 Not modified | 306 (unused) |
307 Temporary redirect | |
400 Bad request | 401 Unauthorized |
402 Payment required | 403 Forbidden |
404 Not found | 405 Method not allowed |
406 Not acceptable | 407 Proxy auth required |
408 Timeout | 409 Conflict |
410 Gone | 411 Length required |
412 Preconditions failed | 413 Request entity too large |
414 Requested URI too long | 415 Unsupported media |
416 Bad request range | 417 Expectation failed |
500 Server error | 501 Not implemented |
502 Bad gateway | 503 Service unavailable |
504 Gateway timeout | 505 Bad HTTP version |
由于各种原因,RESTful API 可能比上面显示的更复杂。
RESTful APIs 已知的主要问题
在许多方面,例如内容交付上,REST 都是一个不错的机制,它也很好得为我们服务了二十多年。但是是时候打破沉默了,承认 RESTful API 可能是在 web 软件中广泛使用的最糟糕的想法之一。
我们很快将看到更好的构建互联网 API 的方式,但在完全领会这个解决方案之前,我们首先得知道 RESTful APIs 的 5 个主要问题,它们使 API 昂贵,冗余,并且容易出错。
问题 #1: 关于 RESTful API 是什么,几乎达不成共识
没有人能够在全部的请求方法,实体和响应状态码的真正含义上达成一致。
设想一下,例如,我们应该用 200 OK
表示成功的更新了一条记录还是要用 201 Created
?看上去我们应该用 250 Updated
,但是这个状态码并不存在。而且谁能向我解释一下 417 Expectation failed
的真正含义。当然指除了 Roy 之外的人。
HTTP 方法和响应状态码的词汇过于模糊和不完整,无法就其语义达成一致。至少在我所知道的,没有任何管理机构能召集大家一起把事情讲清楚。一个公司定义的 200 OK
必然与另一家公司定义的有细微且令人讨厌的区别。这意味着一个 RESTful 模式不能像我们想要的那样可以预测。
问题 #2: REST 词汇的支持不完全
即使就 REST 的各个语义达成一致,我们还会遇到另一个实际的问题:大部分客户端和服务器程序不能完全支持 HTTP 协议 里定义的动词或响应状态码。例如,大部分浏览器对 PUT
或 DELETE
仅提供有限的支持。并且很多服务端程序通常也不能正确地实现这些方法。
那么我们如何突破这些限制呢?一种常用的方法是在浏览器的表单里嵌入预期的请求方法。这意味着 REST 请求现在包含:
- 一个 HTTP 请求方法, 如
POST
- 一个请求地址, 如
/object/list
- 一个我们实际期望的方法,嵌入在请求的实体中,如
DELETE
- 请求实体本身,如表单字段数据
响应状态码的处理也好不到哪去。不同的 web 浏览器 (或者服务器) 对响应状态码的解释也经常各不一样。例如,如果遇到 307 Temporary redirect
状态码,一个浏览器可能允许客户端 JavaScript 在重定向之前处理响应并取消它,另一个浏览器可能就禁止客户端 JavaScript 处理响应。所有程序中真正可靠的响应状态码只有 200 OK
和 500 Internal server error
。除此之外,支持程度一个比一个糟糕。因此,我们也常常可以看到在返回的的实体里嵌入有实际想要的响应状态码。
当然,即使我们能让每个人都对什么是 REST 达成一致,并神奇地修复所有已连入互联网的程序对 REST 支持的缺陷。
问题 #3: REST 词汇对 APIs 来说不够丰富
REST 的方法和响应状态码太过于局限,无法有效地表示所有应用程序所需的各种请求和响应。想一下,我们创建了一个应用程序,并要向 HTTP 客户端 发送一个 “render complete” 响应。我们不能使用 HTTP 响应状态码,因为它不存在并且 HTTP 不能扩展。
还有另外一个问题:HTTP 响应状态码 (200, 201, 202 等) 是和 HTTP 请求方法 (GET
, POST
等)没有直接联系的数字,而我们的实体载荷通常是 JSON 格式。所以执行 REST 请求就好像发送一个目的地是斯瓦希里却包含英语内容的包裹,并通过打鼓声来获得交付确认。这种复杂性往往会造成巨大的困惑和错误。它给我们带来了下一个问题:调试。
问题 #4: RESTful APIs 非常难调试
如果你曾经用过 RESTful API,你大概知道他们几乎难以调试。这是因为我们必须查看 7 个不同的地方来整理出一个完整的事务中发生了什么:
- HTTP 请求方法, 如
POST
- 请求地址, 如
/object/list
- 请求实体中嵌入的实际期望的方法,如
DELETE
- 请求实体中的实际数据,如 表单数据
- 响应状态码,如
200 OK
- 响应实体中嵌入的实际期望的响应状态码,如
206 Partial content
- 响应实体中的实际数据
我们的问题不仅有两个 REST 词汇上的限制,大家就语义达不成一致。现在还有需要查找 7 个不同的地方才可能完全理解和调试一个事务。唯一还能使这更糟的事是,REST 完全绑定到了一个协议上,而不适用于任何其他的协议。当然,这也是我们的下一个问题。
问题 #5: RESTful APIs 通常绑定在 HTTP 上
RESTful API 打破了良好通信的一个基本原则:消息内容应该独立于传输通道。将两者混合来迷惑读者是一个历史悠久的方法。
将 HTTP 协议 与事务的意义混合使得 RESTful API 完全不可移植。将 RESTful API 从 HTTP 迁移 到其他传输协议上需要从 7 个不同的地方解构和重组信息,我们再使用这些信息对 RESTful 请求的全部含义进行编码。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于