使用REST相比非REST HTTP的优势是什么?

176

14个回答

178

我认为你不太可能得到一个好的答案,部分原因是因为没有人真正同意REST的定义。维基百科页面充斥着流行语,但解释很少。讨论页值得一读,因为里面有很多人对此存在争议。据我所知,REST 的意思是这样的:

不采用随意命名的 setter 和 getter URL,并在所有 getter 中使用 GET,在所有 setter 中使用 POST,而是尝试让 URL 标识资源,并使用 HTTP 动作GETPOSTPUTDELETE来对其进行操作。所以,我们不再使用类似于下面的方式:

GET /get_article?id=1
POST /delete_article   id=1

你可以这样做

GET /articles/1/
DELETE /articles/1/

然后POSTPUT分别对应“创建”和“更新”操作(但没有人同意哪个是哪个)。

我认为缓存参数是错误的,因为查询字符串通常被缓存,而且你不一定需要使用它们。例如Django可以轻松地实现这样的功能,但我不会说它是RESTful的:

GET /get_article/1/
POST /delete_article/     id=1

甚至可以将动词直接包含在URL中:

GET /read/article/1/
POST /delete/article/1/
POST /update/article/1/
POST /create/article/
在这种情况下,GET 表示没有副作用的操作,而 POST 表示会在服务器上更改数据的操作。我认为这样可能会更加清晰和易于理解,尤其是你可以避免整个 PUT vs POST 的问题。此外,如果需要,您可以添加更多的动词,因此您不必人为地受限于HTTP所提供的内容。例如:
POST /hide/article/1/
POST /show/article/1/

(或其他什么,直到它们发生才难以想出例子!)

因此,总的来说,我只能看到两个优点:

  1. 您的 Web API 可能更清晰、更易于理解/发现。
  2. 在与网站同步数据时,使用 REST 可能更容易,因为您只需要说 synchronize("/articles/1/") 或其他什么。这在很大程度上取决于您的代码。

但是我认为有一些相当大的缺点:

  1. 并非所有操作都很容易映射到 CRUD(创建、读取/检索、更新、删除)。您甚至可能不处理对象类型的资源。
  2. 这是为了可疑的好处而付出额外的努力。
  3. 关于 PUTPOST 的顺序混乱。在英语中,它们的意思相似(“我要在墙上放/发布一个通知。”)。

因此,总结一下,我会说:除非您真的想要付出额外的努力,或者如果您的服务与 CRUD 操作非常匹配,请将 REST 留给 API 的第二个版本。


我刚刚遇到 REST 的另一个问题:在一个请求中执行多个操作或指定要获取的复合对象的哪些部分不容易。这在移动设备上尤其重要,因为往返时间可能很长,而连接也不可靠。例如,假设您正在获取 Facebook 时间线上的帖子。“纯粹”的 REST 会像这样:

GET /timeline_posts     // Returns a list of post IDs.
GET /timeline_posts/1/  // Returns a list of message IDs in the post.
GET /timeline_posts/2/
GET /timeline_posts/3/
GET /message/10/
GET /message/11/
....

这有点荒谬。在我看来,Facebook的API非常棒,那么让我们看看他们是如何做到的:

默认情况下,在查询时返回大多数对象属性。您可以使用“fields”查询参数选择要返回的字段(或连接)。例如,此URL仅返回Ben的id、name和picture: https://graph.facebook.com/bgolub?fields=id,name,picture

我不知道如何用REST实现这样的功能,即使你这样做了,它是否仍然算作REST也不确定。但无论如何,我肯定会忽略任何试图告诉你不应该这样做的人(特别是如果原因是“因为它不是REST”)!


5
根据HTTP RFC,POST和PUT应该被用于不同的情况。在这种情况下,PUT表示在特定位置创建/更新某些内容-这取决于URI是否已经存在内容(并且它是幂等的),而POST表示您请求Web服务确定要发送的内容放在哪里,然后它返回URI(因此只能创建)。如果涉及计算机之外的任何内容,使用DELETE就无法抱怨英语问题了。不过,我对你编辑提出的问题感到疑惑,不知道该如何处理 :P - Nan L
7
对我而言,Facebook API 的示例看起来像是 REST(实际上比使用 URL 中动词的示例更符合)。查询参数也可以符合 RESTful,只是最好使用可以按层次排列数据的路径。请注意,这是一份翻译,不包含解释和任何额外内容。 - Justin Emery
5
只要您不在查询字符串中引用资源,它们就是完全符合RESTful的。我倾向于将它们视为可以调整端点行为的过滤器。 - Sinaesthetic
3
REST是一个非常特定的概念,由Roy Fielding在其发明时所描述。参见此答案,尤其是其中的这句话:“客户端只需要知道初始URI,并随后从服务器提供的选择中选择导航或执行操作。”基本上,如果API的任何部分记录了终点,例如说“给定用户ID,可以在/user/{id}获取用户信息”,那么它就不是RESTful的。请考虑一下:你的浏览器是否需要预先程序化地知道如何获取Stack Overflow问题页面的HTML? - Claudiu
1
其他人滥用这个术语并不改变它的本质。但需要声明的是:我仍在学习REST是什么,这是我最近领悟到的。 - Claudiu
显示剩余12条评论

53

简单来说,REST 意味着使用 HTTP 的标准方式。

可以阅读 Roy Fielding 关于 REST 的论文。我认为每个从事 web 开发的人都应该阅读。

需要注意的是,Roy Fielding 也是 HTTP 协议背后的重要推动者之一。

以下是一些优势:

  • 简单易懂。
  • 你可以充分利用 HTTP 缓存和代理服务器来帮助处理高负载。
  • 它可以将一个非常复杂的应用程序组织成简单的资源。
  • 即使你没有专门为新客户端设计应用程序(可能是因为他们在你创建应用时还不存在),也很容易让他们使用。

14
"简单": 为什么REST比HTTP更简单? REST相对于HTTP更简单的原因在于它是一种架构风格,而HTTP只是实现REST的一种方式。REST强调使用统一的接口来访问资源,通过HTTP协议中的GET、POST、PUT和DELETE方法来实现,并使用URI来唯一标识资源。这使得REST的实现更加简单直观,同时也有利于提高系统的灵活性和可扩展性。 - Dimitri C.
6
“帮助您组织”: 仅使用GET和POST时,这种组织方式更加困难吗? - Dimitri C.
27
遵循REST约束绝对不简单。有时将复杂的业务操作压缩成四个标准动词实际上非常困难。但是,如果做得好,最终结果可能很容易理解,但达到这一点却并不容易。 - Darrel Miller
7
@Dimitri: “Simple”因为它为您提供一个简单的框架来进行操作。REST 就是 HTTP!它比SOAP(甚至在名称中都有“简单”一词)要简单得多。“帮助您组织” - 这个概念并不难理解,一旦正确实施,它可以让事情变得更好。 REST可以被视为设计应用程序的一种方式,而不是实现细节。正如Darrel所指出的,实施它可能不容易,但结果是有回报的。“它使新客户端很容易使用您的应用程序” - 再次强调:REST 就是 HTTP。 - Emil Ivanov
1
@DarrelMiller 我以为只有我这么想。我的API有时需要多个变量,将所有内容塞进REST格式中有点困难,以某种方式使其“更简单”。 - johnny
显示剩余5条评论

33

简单来说:没有

请随意点踩,但我仍然认为与非REST HTTP相比没有真正的好处。所有当前的答案都是无效的。以下是目前得票最多的答案中的论点:

  • 简单。
  • 您可以充分利用HTTP缓存和代理服务器来帮助您处理高负载。
  • 它使你能够将一个非常复杂的应用程序组织成简单的资源。
  • 即使您没有特别为新客户端设计(可能是因为他们在您创建应用程序时还不存在),REST也使得他们能够轻松使用您的应用程序。

1. 简单

使用REST需要为服务端和客户端脚本提供额外的通信层=>实际上比非REST HTTP更复杂。

2. 缓存

缓存可以通过服务器发送的HTTP头来控制。REST不会增加任何非REST所缺少的功能。

3. 组织

REST并不会帮助您组织事物。它强制您使用由您正在使用的服务端库支持的API。当您使用非REST方法时,您可以以相同或更好的方式组织应用程序。例如,请参见模型-视图-控制器MVC路由

4. 易于使用/实现

并不完全正确。这完全取决于您如何组织和记录您的应用程序。REST不会神奇地使您的应用程序变得更好。


3
通常REST API更容易被缓存,因为您将数据分离成具有相同生命周期(同时创建和更新)的资源,所以您可以可靠地进行缓存并清除缓存 - 而非REST API通常返回已进行大量后处理或是多个实体组合而成的数据,这使得缓存变得更加困难。 - Scott Schulthess
2
正确的是它不是互斥的(你可以有一个非REST API是可缓存的),但采用REST方法来设计API会鼓励并实践中肯定相关,因为它鼓励各种最佳实践(可发现性、通用接口、可缓存性、智能资源建模)。 - Scott Schulthess
4
REST无法帮助你组织事物,它强制你使用与所使用的服务器端库支持的API。 - Michael O.
2
使用REST时,您需要额外的通信层 - 这是胡说,您完全可以使用现有的HTTP库。 - Søren Boisen
2
我很难过这么多人点赞了这个。你所建议的是HTTP有缓存头...好吧,HTTP使用REST原则。这就是为什么REST很棒。REST不是扩展HTTP的东西...REST只是一系列网络协议的要求,而HTTP遵守这些要求...我们的API应该遵守这些要求,因为HTTP很棒,为什么要重新发明轮子,而不是让我们的API利用HTTP功能并保持RESTful..duhhh.....我停不下来加更多的点.... - EralpB
显示剩余6条评论

27

在我看来,REST最大的优势是减少客户端/服务器之间的耦合程度。使用REST接口更容易随着时间的推移进行演进而不会破坏现有的客户端。


4
你能举个例子吗?谢谢! - Jan Żankowski
3
这取决于你的非REST API抽象程度,是吗? - johnny
@DarrelMiller,您能否详细说明REST如何比非REST的http方法更好地减少客户端/服务器耦合?我相信您指的是Timmmm在他/她的答案中提到的观点。请查看我在Timmmm答案下的最新评论。 - emilly
1
REST系统不依赖于带外信息来处理响应。对于特定请求可能返回的内容,不需要做出任何假设。响应会告诉你一切你需要知道的信息。这使得服务器可以更改其行为,客户端可以意识到这些变化。 - Darrel Miller
1
@emilly 是的,REST 约束告诉你如何使用像 HTTP 这样的协议来实现可演化的系统,但这并不意味着人们不会以不遵循这些指南的方式使用 HTTP。几乎每个返回 Content-Type: application/json 的 API 都有依赖于带外知识从该有效负载中获取语义信息的客户端。这违反了 REST 的约束,但不违反 HTTP 规范。 - Darrel Miller
显示剩余2条评论

17

发现性

每个资源都引用了其他资源,可以通过层次结构或链接轻松浏览。这对于开发客户端的人来说是一个优势,免去了不断查阅文档并提供建议的麻烦。它还意味着服务器可以单方面更改资源名称(只要客户端软件没有硬编码URL)。

与其他工具的兼容性

您可以使用CURL访问API的任何部分,或使用Web浏览器导航资源。这样可以更容易地进行调试和测试集成。

标准化动词名称

允许您指定操作而无需寻找正确的措辞。想象一下如果OOP属性的getter和setter没有标准化,有些人使用retrievedefine。您将不得不记忆每个单独访问点的正确动词。知道只有少量动词可用就可以解决这个问题。

标准化状态

在RESTful API中,如果您 GET 不存在的资源,您可以确保会收到404错误。这与非RESTful API形成对比,后者可能会返回包装在各种层中的{error:"未找到"}。如果您需要额外的空间向另一侧开发者编写消息,您始终可以使用响应的正文部分。

例子

想象两个具有相同功能的API,一个遵循REST,另一个不遵循。现在想象以下这些API的客户端:

RESTful:

GET /products/1052/reviews
POST /products/1052/reviews       "5 stars"
DELETE /products/1052/reviews/10
GET /products/1052/reviews/10

HTTP:

GET /reviews?product_id=1052
POST /post_review?product_id=1052                  "5 stars"
POST /remove_review?product_id=1052&review_id=10
GET /reviews?product_id=1052&review=10

现在考虑以下问题:

  • 如果每个客户端的第一个调用都有效,您对其余的调用是否有信心也会有效?

  • API 进行了重大更新,可能已更改这些访问点。你需要重新阅读多少文档?

  • 你能预测最后一个查询的返回结果吗?

  • 在删除之前,你必须编辑发布的评论。你能在不查看文档的情况下完成吗?


1
这不应该是一个详尽的列表,仅包含非常实用的优点。 - BoppreH
1
这是一个非常聪明的回答,我赞同。 - EralpB

10

我建议看一下Ryan Tomayko的《如何向妻子解释REST》

第三方编辑

从waybackmaschine链接中摘录:

举个例子,你是一名教师,想管理学生:

  • 他们所在的班级,
  • 他们的成绩,
  • 紧急联系人,
  • 有关所使用的教材的信息等。

如果这些系统都是基于网络的,那么每个涉及到的名词都可能有一个URL:student、teacher、class、book、room等。 ... 如果每个URL都有一个机器可读的表示形式,那么将新工具连接到系统中就非常简单了,因为所有的信息都可以以标准方式被消费。... 你可以建立一个全国性的系统,能够与每个单独的学校系统对话,以收集测试分数。

每个系统都使用简单的HTTP GET从彼此获取信息。如果一个系统需要向另一个系统添加内容,则使用HTTP POST。如果一个系统想要更新另一个系统中的内容,则使用HTTP PUT。唯一留下的问题是数据应该长什么样子。


6
妻子:这是另一个机器人的事吗? - Tobu
4
这是一篇不错的文字,但它没有举例说明为什么在所有情况下都使用GET和POST会有问题。 - Dimitri C.
9
所以我试图发现为什么它更好 :-) - Dimitri C.
7
文件已被删除。 - surfen
2
@surfen waybackmachine - felickz
显示剩余3条评论

4
我建议每个寻找答案的人都浏览this "幻灯片"。我之前无法理解REST是什么,为什么它如此酷,它的优缺点以及与SOAP的区别-但这个幻灯片非常精彩易懂,现在对我来说比以前更加清晰了。

3

缓存。

REST有许多更深入的好处,涉及通过松耦合和超文本实现可演化性,但缓存机制是你应该关心RESTful HTTP的主要原因。


3
可以举个例子说明哪些内容可能会被缓存,以及为什么非REST解决方案无法进行缓存? - Dimitri C.
2
@Dimitri C.:一个链接 http://www.wikipedia.org/article?id=19 由于忽略url中传递的参数而无法被代理缓存。另一方面,链接http://www.wikipedia.org/REST可以被缓存,明白吗? - VP.
6
如果缓存是REST的主要好处,我可以向您保证,我不会花费过去两年时间来构建RESTful服务。 - Darrel Miller
Darrel,你可能正在构建分布式规模的系统,其中松耦合是最重要的(想知道这些系统的类型),但大多数人不是这样做的 - 或者他们正在使用技术(即浏览器和HTML),其中大部分繁重的工作已经为他们完成了。 - Mike
1
那么如果缓存是您的关注点,为什么不只使用GET /get_article/19/POST /update_article?您仍然可以只用GETPOST完成所有操作,并且我认为REST意味着“仅使用GETPOSTPUTDELETE”,而不仅仅是“不要使用查询字符串”。因此,我的建议不会符合REST。不过,毕竟没有人真正同意REST到底是什么,所以我把它放在一个和“Web 2.0”一样的桶里。 - Timmmm

3

这些内容可以在Fielding dissertation中找到,但如果你不想阅读太多:

  • 增加可伸缩性(由于无状态、缓存和分层系统的限制)
  • 解耦客户端和服务器(由于无状态和统一接口的限制)
    • 可重用的客户端(客户端可以使用通用REST浏览器和RDF语义来决定要跟踪哪个链接以及如何显示结果)
    • 非破坏性的客户端(客户端仅通过应用程序特定的语义更改而破坏,因为它们使用语义而不是某些API特定的知识)

0

@Timmmm,关于你的编辑:

GET /timeline_posts     // could return the N first posts, with links to fetch the next/previous N posts

这将大大减少调用次数。

而且,您可以设计一个服务器,接受HTTP参数来表示客户端可能需要的字段值...

但这只是一个细节。

更重要的是,您没有提到REST架构风格的巨大优势(由于服务器无状态性,可实现更好的可扩展性;由于服务器无状态性,可实现更好的可用性;使用REST架构风格时,可以更好地利用标准服务,例如缓存等;由于使用统一接口,客户端和服务器之间的耦合度更低等等)

至于您的评论:

"并非所有操作都容易映射到CRUD(创建、读取/检索、更新、删除)."

:RDBMS也使用CRUD方法(SELECT / INSERT / DELETE / UPDATE),并且总有一种方法来表示和处理数据模型。

关于您的句子:

"您甚至可能不涉及对象类型资源"

RESTful 设计本质上是一种简单的设计,但这并不意味着设计它很简单。你看出区别了吗?你需要深入思考你的应用程序将代表和处理的概念,必须通过资源来表示它,或者更确切地说,你需要思考它必须完成什么任务。但如果你这样做,最终会得到一个更简单、更高效的设计。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接