REST和RPC之间的Web服务差异

230

我有一个接受JSON参数并具有特定方法URL的Web服务,例如:

http://IP:PORT/API/getAllData?p={JSON}

这绝对不是符合REST的标准,因为它不是无状态的。它会考虑cookie并拥有自己的会话。

那它是RPC吗?RPC和REST有什么区别?


1
为什么REST和RPC很重要?你问这个问题的原因是什么?(我试图理解问题的背景,以便更好地制定答案。) - Bogdan
17
这项服务不是我的,它标注为REST,但似乎并不是。我想知道自己是否对其不属于REST有误解。 - Mazmart
11个回答

304
考虑以下关于模拟餐厅订单的HTTP API的示例。
- RPC API以“动词”为思维方式,将餐厅功能作为函数调用暴露出来,接受参数,并通过最合适的HTTP动词调用这些函数 - 查询使用'get'等。但是动词的名称纯粹是附带的,与实际功能无关,因为每次都会调用不同的URL。返回代码是手工编码的,并且是服务合同的一部分。
- 相比之下,REST API将问题域中的各种实体建模为资源,并使用HTTP动词表示对这些资源的事务 - 使用POST创建,PUT更新和GET读取。在相同的URL上调用所有这些动词提供不同的功能。常见的HTTP返回代码用于传达请求的状态。
下订单:
  • RPC: http://MyRestaurant:8080/Orders/PlaceOrder (POST: {Tacos object}<! --Rest of the order-->)
  • REST: http://MyRestaurant:8080/Orders/Order?OrderNumber=asdf (POST: {Tacos object}<! --Rest of the order-->)

Retrieving an Order:

  • RPC: http://MyRestaurant:8080/Orders/GetOrder?OrderNumber=asdf (GET)
  • REST: http://MyRestaurant:8080/Orders/Order?OrderNumber=asdf (GET)

Updating an Order:

  • RPC: http://MyRestaurant:8080/Orders/UpdateOrder (PUT: {Pineapple Tacos object}<! --Rest of the order-->)
  • REST: http://MyRestaurant:8080/Orders/Order?OrderNumber=asdf (PUT: {Pineapple Tacos object}<! --Rest of the order-->)

示例取自sites.google.com/site/wagingguerillasoftware/rest-series/what-is-restful-rest-vs-rpc


113
最后给出一些网址示例。 - fabpico
10
关于URL的问题,我不同意你说的话。你完全可以将所有的RPC调用放在同一个URL上,而将REST调用放在不同的URL上。你只是展示了硬币的一面。 - basickarl
1
你在这里描述的不是REST - REST是一种架构模式。你所描述的是基于HTTP的REST,这是大多数人谈论REST时想到的内容。 - d4nyll
13
@basickarl,我不喜欢人们以负面的方式评论,但又没有给出更好的回答。 - Soner from The Ottoman Empire
1
简而言之,RPC 侧重于“行动”,而 REST 侧重于“资源”。 - Gelmir
url Orders/Order 从我的角度来看不好看 - gstackoverflow

143

仅凭您发布的内容无法清楚地区分REST或RPC。

REST的一个约束是它必须是无状态的。如果您有会话,那么您就有状态,因此您不能将服务称为RESTful。

在您的URL中有一个动作(即getAllData),这表明其属于RPC。在REST中,您交换表示,并且执行的操作由HTTP动词指定。此外,在REST中,内容协商不使用?p={JSON}参数进行。

不知道您的服务是否为RPC,但它不是RESTful的。您可以在网上了解区别,这里是一篇文章供您入门:RPC和REST的神话破冰。您更了解自己的服务内部情况,因此请将其功能与RPC进行比较,然后得出自己的结论。


1
因此,RESTful表示它遵守除REST之外的所有标准,当它选择不遵守标准时呢? - Mazmart
14
@Mazmart:REST是一组指导方针和约束条件。它不是一个可以实现的规范,也不能仅靠宣称自己有RESTful服务就拥有它。从我注意到的情况来看,大多数人所谓的REST其实只是其他某种类型的RPC,并非SOAP之外的一切内容。 - Bogdan
“Debunking the Myths of PRC & REST” 的链接将我转到了 Tyson Trautmann 的 Twitter 页面。 - Jai dewani
3
@Jaidewani:我用一个来自存档的链接替换了损坏的链接,该链接是回答撰写时的链接。 - Bogdan
4
现实生活中的例子:如何请求10000个股票的last_price?由于GET限制,无法实现。POST可以,但这会违反华丽的学术REST修辞。 - comte

130

正如其他人所说,一个关键的区别在于REST URL以名词为中心,而RPC URL以动词为中心。我只想包括这个具有清晰示例的表格来说明:

---------------------------+-------------------------------------+--------------------------
 操作                 | RPC(操作)                     | REST(资源)
---------------------------+-------------------------------------+--------------------------
 注册                    | POST /signup                        | POST /persons           
---------------------------+-------------------------------------+--------------------------
 辞职                    | POST /resign                        | DELETE /persons/1234    
---------------------------+-------------------------------------+--------------------------
 读取个人信息               | GET /readPerson?personid=1234       | GET /persons/1234       
---------------------------+-------------------------------------+--------------------------
 读取个人物品列表  | GET /readUsersItemsList?userid=1234 | GET /persons/1234/items 
---------------------------+-------------------------------------+--------------------------
 向个人物品列表添加物品 | POST /addItemToUsersItemsList       | POST /persons/1234/items
更新项目 | POST /modifyItem | PUT /items/456 删除项目 | POST /removeItem?itemId=456 | DELETE /items/456
说明: - 如表所示,REST 倾向于使用 URL 路径参数来标识特定的资源(例如,GET /persons/1234),而 RPC 倾向于使用查询参数作为函数输入(例如,GET /readPerson?personid=1234)。 - 表中未显示如何使用 REST API 进行筛选,通常涉及查询参数(例如,GET /persons?height=tall)。 - 同样未显示的是当您进行创建/更新操作时,可能会通过消息正文传递其他数据(例如,当您进行 POST /signup 或 POST /persons 时,包括描述新人员的数据)。
  • 当然,这些并非一成不变的规则,但它们可以让你了解到可能会遇到的问题,以及如何为保持一致性而组织自己的 API。有关 REST URL 设计的进一步讨论,请参见这个问题

  • 15
    尽可能简洁明了地解释,避免冗长的文本和链接,清晰准确地表达观点。 - theAnonymous
    4
    我读到这篇答案之前就有一种感觉:哇,这些答案虽然是用英语写的,但我真的无法理解它们在说什么。 - avocado
    1
    鉴于表格中显示的差异,我们选择RPC而不是REST的特定原因是什么?例如,如果RPC性能更好(如果是这样,为什么)? - avocado
    我不明白为什么有人认为RPC是以动词为中心,而REST是以名词为中心,因为REST非常注重对同一名词(端点)使用的动词。同样地,我也不知道为什么RPC被标记为以动词为中心,因为动词通常可以是任意的,只要使用不同的名词(端点)和查询数据的组合即可。除此之外,我理解这个答案。 - cpk
    1
    @rolaids_guy 你提出了一个有价值的观点。我的意思是,对于RPC来说,URLs通常是动词,而对于REST来说则是名词。我进行了编辑以澄清。 - MarredCheese

    62

    这是使用HTTP的RPC。正确实现REST应该与RPC有所不同。具有处理数据逻辑的类似方法/函数的方式属于RPC。getAllData()是一种智能方法。REST不能具有智能性,它应该是可以由外部智能查询的愚笨数据。

    我最近看到的大多数实现都是RPC,但许多人错误地称其为REST。REST与HTTP结合是救世主,SOAP与XML相对而言糟糕。所以你的困惑是合理的,你是正确的,它不是REST。但请记住,REST并不新(2000年),尽管SOAP/XML很旧,json-rpc稍后出现(2005年)。

    HTTP协议本身并不能构建REST实现。REST(GET、POST、PUT、PATCH、DELETE)和RPC(GET + POST)两者都可以通过HTTP进行开发(例如:通过Visual Studio中的Web API项目)。

    不过,那么REST是什么呢?以下是Richardson成熟度模型(摘要),只有第3级才是符合REST原则的。

    • Level 0: Http POST(级别0:Http POST)
    • Level 1: each resource/entity has a URI (but still only POST)(级别1:每个资源/实体都有一个URI(但仍然只能使用POST))
    • Level 2: Both POST and GET can be used(级别2:可以同时使用POST和GET)
    • Level 3(RESTful): Uses HATEOAS (hyper media links) or in other words self exploratory links(级别3(RESTful):使用HATEOAS(超媒体链接),或者换句话说,自我探索链接)

    例如:级别3(HATEOAS):

    1. 链接说明此对象可以通过这种方式进行更新,并且可以通过这种方式进行添加。

    2. 链接说明此对象只能被读取,以及如何读取。

      显然,仅发送数据还不足以成为REST,但是如何查询数据也应该提到。但再次问一下,为什么要有4个步骤?为什么不能只有第4步并称之为REST?Richardson只是给了我们一个逐步接近目标的方法而已。

    最后一个问题:为什么我们需要一个链接来解释如何调用它?任何程序员只需查看端点就知道如何调用API。或者在最坏的情况下,只需联系开发人员并询问!

    你已经建立了可以被人类使用的网站。但是你能否也建立出可以被机器使用的网站呢?这就是未来的方向,而《RESTful Web Services》会告诉你如何做到。

    1
    第一段非常简单明了地解释了区别。我点赞 :) - Nikolas Charalambidis

    24

    REST的最佳应用是处理资源,而RPC更多涉及操作。

    REST代表表述性状态转移。它是组织独立系统之间交互的简单方法。 RESTful应用通常使用HTTP请求发布数据(创建和/或更新),读取数据(例如,进行查询)和删除数据。因此,REST可以使用HTTP执行所有四个CRUD(创建/读取/更新/删除)操作。

    RPC主要用于不同模块之间的通信,以响应用户请求。 例如,在openstack中,当启动虚拟机时,如何让nova、glance和neutron一起工作。


    14

    分享的URL看起来像是RPC终端点。 以下是RPC和REST的示例。希望这有助于理解它们何时可以使用。

    让我们考虑一个终端点,向客户发送应用程序维护中断电子邮件。

    此终端点执行一个特定的操作。

    RPC

    POST https://localhost:8080/sendOutageEmails
    
    BODY: {"message": "we have a scheduled system downtime today at 1 AM"}
    

    REST

    POST https://localhost:8080/emails/outage
    
    BODY: {"message": "we have a scheduled system downtime today at 1 AM"}
    

    在这种情况下,使用RPC端点更加合适。当API调用执行单个任务或操作时,通常会使用RPC端点。显然,我们可以像所示一样使用REST,但是该端点不太符合RESTful的规范,因为我们没有对资源执行操作。

    现在让我们看一个将数据存储在数据库中的端点。(典型的CRUD操作)

    RPC

    POST https://localhost:8080/saveBookDetails
    
    BODY: {"id": "123", "name": "book1", "year": "2020"}
    

    REST

    POST https://localhost:8080/books
    
    BODY: {"id": "123", "name": "book1", "year": "2020"}
    

    REST在这种情况下(CRUD)要好得多。在这里,可以使用适当的HTTP方法来读取(GET)、删除(DELETE)或更新(PUT)。方法决定了资源(在这种情况下为“books”)上的操作。 在这里使用RPC不合适,因为我们需要为每个CRUD操作(/getBookDetails、/deleteBookDetails、/updateBookDetails)设置不同的路径,并且对应用程序中的所有资源都必须这样做。

    总之,

    • RPC可用于执行单个特定操作的端点。
    • REST用于需要CRUD操作的端点。

    Slack使用这种风格的HTTP RPC Web API's - https://api.slack.com/web


    10
    这里有许多好的答案。我仍然建议您参考Google博客,因为它非常好地讨论了RPC和REST之间的区别,并捕捉到了在这里任何答案中都没有读到的内容。
    我想引用同一链接中引起我注意的一段话:
    REST本身是描述支撑HTTP和全球网络的设计原则。但由于HTTP是唯一一个商业上重要的REST API,我们可以大部分避免讨论REST,只关注HTTP。这种替代很有用,因为人们在API上下文中认为REST意味着什么存在很多困惑和不确定性,但对于HTTP本身,有更大的清晰度和协议。 HTTP模型是RPC模型的完美相反——在RPC模型中,可寻址单元是过程,并且问题域的实体被隐藏在过程后面。而在HTTP模型中,可寻址单元是实体本身,系统行为被隐藏在实体后面作为创建、更新或删除它们的副作用。

    6

    我会这样说:

    我的实体是否持有/拥有数据?如果是,则使用RPC:这里是一份部分数据的副本,请操作我发送给你的数据副本并将您的结果返回给我。

    被调用实体是否持有/拥有数据?则使用REST:要么(1)向我展示一份部分数据,要么(2)操作一些数据。

    最终关键在于哪个“方”拥有/持有数据。是的,你可以使用REST措辞与基于RPC的系统交谈,但这样做仍然会进行RPC活动。

    例子1:我有一个对象通过DAO与关系型数据库存储区(或任何其他类型的数据存储区)进行通信。在我的对象和可以作为API存在的数据访问对象之间进行交互时,使用REST风格是有道理的。我的实体不拥有/持有数据,关系型数据库(或非关系型数据存储区)拥有/持有数据。

    例子2:我需要进行大量复杂的数学计算。我不想将许多数学方法加载到我的对象中,我只想将一些值传递给其他能够进行各种数学计算的东西,并获得结果。然后RPC风格是有意义的,因为数学对象/实体将向我的对象公开大量操作。请注意,这些方法可能都会作为单独的API公开,并且我可以使用GET调用它们中的任何一个。我甚至可以声称这是符合REST原则的,因为我通过HTTP GET进行调用,但实际上在幕后进行的是RPC。我的实体拥有/持有数据,远程实体只是对我传递给它的数据副本进行操作。


    4

    在HTTP协议下,它们最终只是HttpRequest对象,并且都期望返回一个HttpResponse对象。我认为可以根据这个描述继续编码,然后考虑其他事情。


    4

    以下是我对它们在不同应用场景中的理解和使用方法:

    例子:餐厅管理

    REST的使用场景: 订单管理

    - create order (POST), update order (PATCH), cancel order (DELETE), retrieve order (GET)
    - endpoint: /order?orderId=123
    

    对于资源管理,REST非常简洁。一个端点包含预定义的操作。它可以被看作是将数据库(Sql或NoSql)或类实例暴露给全世界的一种方式。

    实现示例:

    class order:
        on_get(self, req, resp): doThis.
        on_patch(self, req, resp): doThat.
    

    框架示例:Python的Falcon。

    RPC的使用案例:操作管理

    - prepare ingredients: /operation/clean/kitchen
    - cook the order: /operation/cook/123
    - serve the order /operation/serve/123
    

    针对分析、操作性、非响应式、非代表性、基于行动的工作,RPC的效果更好,而且函数式思维也很自然。

    实现示例:

    @route('/operation/cook/<orderId>')
    def cook(orderId): doThis.
    
    @route('/operation/serve/<orderId>')
    def serve(orderId): doThat.
    

    框架示例:Python的Flask


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