题 RESTful编程究竟是什么?


RESTful编程究竟是什么?


3630
2018-03-22 14:45


起源


请参阅以下链接的答案 stackoverflow.com/a/37683965/3762855 - Ciro Corvino
REST现在可能会变得有点旧;) youtu.be/WQLzZf34FJ8 - Vlady Veselinov
另外,请参阅此链接以获取更多信息 news.ycombinator.com/item?id=3538585 - Ashraf.Shk786
这里更正了接受的答案。 stackoverflow.com/questions/19843480/...  或者在这里 roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven  或者在这里 web.archive.org/web/20130116005443/http://tomayko.com/writings/... - kushalvm
@ OLIVER.KOO很好的观察。只是我在一个新事物的时候问过它。它被抛出了很多,但没有多少人知道它是什么。至少我没有,似乎我问这个有帮助他们,因为他们也想知道。 - hasen


答案:


一个 建筑风格 叫 REST(代表性国家转移) 主张Web应用程序应该使用HTTP 最初设想的。查找应该使用 GET 要求。 PUTPOST,和 DELETE 要求 应该用于 分别是变异,创造和删除

REST支持者倾向于支持URL,例如

http://myserver.com/catalog/item/1729

但REST架构不需要这些“漂亮的URL”。带参数的GET请求

http://myserver.com/catalog?item=1729

就像RESTful一样。

请记住,绝不应该使用GET请求来更新信息。例如,向购物车添加商品的GET请求

http://myserver.com/addToCart?cart=314159&item=1729

不合适。 GET请求应该是 幂等。也就是说,两次发出请求应该与发出一次请求没有什么不同。这就是使请求可缓存的原因。 “添加到购物车”请求不是幂等的 - 发布它两次将该项目的两个副本添加到购物车。在这种情况下,POST请求显然是合适的。因此,甚至一个 RESTful Web应用程序 需要它的POST请求份额。

这取自优秀的书 核心JavaServer面临 David M. Geary的书。


541
2018-04-15 11:26



Lisiting可用的幂等操作:GET(安全),PUT和DELETE(此链接中提到了异常restapitutorial.com/lessons/idempotency.html)。安全和幂等方法的附加参考w3.org/Protocols/rfc2616/rfc2616-sec9.html - Abhijeet
a)关于GET的重要一点是安全性,而不是幂等性,b)@Abhijeet:RFC 2616已于2014年废弃;见RF 7230ff。 - Julian Reschke
这是错的。阅读本文以正确解释REST roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven  或这个 stackoverflow.com/questions/19843480/... - kushalvm
@kushalvm在实践中没有使用REST的学术定义。 - Elliott Beach
REST从未打算用于Web API,仅用于静态资源和它们 是 超文本驱动的。然而,菲尔丁在他所有的学术天真中认为,他们将直接从浏览器借助所有这些HTTP动词来维护,这在任何速度或形式都是不实际的。 REST只不过是一堆无用的流行语,应该尽快放弃。 - Vadim Ferderer


休息 是网络的基本架构原则。关于Web的惊人之处在于,客户端(浏览器)和服务器可以以复杂的方式进行交互,而客户端无需事先了解服务器及其承载的资源。关键的限制是服务器和客户端都必须同意 媒体 使用,在网络的情况下是 HTML

符合原则的API 休息 不要求客户端知道有关API结构的任何信息。相反,服务器需要提供客户端与服务交互所需的任何信息。一个 HTML表单 就是一个例子:服务器指定资源的位置和必填字段。 浏览器事先不知道提交信息的位置,并且事先不知道要提交哪些信息。两种形式的信息完全由服务器提供。 (这个原则被称为 HATEOAS:超媒体作为应用程序状态的引擎。)

那么,这是如何适用的 HTTP,它如何在实践中实施? HTTP围绕动词和资源。主流使用的两个动词是GET和POST,我想每个人都会认识到。但是,HTTP标准定义了其他几个,如PUT和DELETE。然后根据服务器提供的指令将这些动词应用于资源。

例如,假设我们有一个由Web服务管理的用户数据库。我们的服务使用基于JSON的自定义超媒体,我们为其分配mimetype 应用/ JSON + USERDB (可能还有一个 应用/ XML + USERDB 和 应用程序/无论+ USERDB  - 可能支持许多媒体类型)。客户端和服务器都已编程为理解这种格式,但他们对彼此一无所知。如 罗伊菲尔丁 指出:

REST API应该花费几乎所有的描述性工作   定义用于表示资源和驾驶的媒体类型   应用程序状态,或定义扩展关系名称和/或   支持超文本的标记,用于现有标准媒体类型。

对基础资源的请求 / 可能会返回这样的内容:

请求

GET /
Accept: application/json+userdb

响应

200 OK
Content-Type: application/json+userdb

{
    "version": "1.0",
    "links": [
        {
            "href": "/user",
            "rel": "list",
            "method": "GET"
        },
        {
            "href": "/user",
            "rel": "create",
            "method": "POST"
        }
    ]
}

我们从媒体的描述中了解到,我们可以从名为“链接”的部分找到有关相关资源的信息。这就是所谓的 超媒体控件。在这种情况下,我们可以从这样的部分告诉我们可以通过发出另一个请求来找到用户列表 /user

请求

GET /user
Accept: application/json+userdb

响应

200 OK
Content-Type: application/json+userdb

{
    "users": [
        {
            "id": 1,
            "name": "Emil",
            "country: "Sweden",
            "links": [
                {
                    "href": "/user/1",
                    "rel": "self",
                    "method": "GET"
                },
                {
                    "href": "/user/1",
                    "rel": "edit",
                    "method": "PUT"
                },
                {
                    "href": "/user/1",
                    "rel": "delete",
                    "method": "DELETE"
                }
            ]
        },
        {
            "id": 2,
            "name": "Adam",
            "country: "Scotland",
            "links": [
                {
                    "href": "/user/2",
                    "rel": "self",
                    "method": "GET"
                },
                {
                    "href": "/user/2",
                    "rel": "edit",
                    "method": "PUT"
                },
                {
                    "href": "/user/2",
                    "rel": "delete",
                    "method": "DELETE"
                }
            ]
        }
    ],
    "links": [
        {
            "href": "/user",
            "rel": "create",
            "method": "POST"
        }
    ]
}

我们可以从这个回复中说出很多。例如,我们现在知道我们可以通过POST来创建一个新用户 /user

请求

POST /user
Accept: application/json+userdb
Content-Type: application/json+userdb

{
    "name": "Karl",
    "country": "Austria"
}

响应

201 Created
Content-Type: application/json+userdb

{
    "user": {
        "id": 3,
        "name": "Karl",
        "country": "Austria",
        "links": [
            {
                "href": "/user/3",
                "rel": "self",
                "method": "GET"
            },
            {
                "href": "/user/3",
                "rel": "edit",
                "method": "PUT"
            },
            {
                "href": "/user/3",
                "rel": "delete",
                "method": "DELETE"
            }
        ]
    },
    "links": {
       "href": "/user",
       "rel": "list",
       "method": "GET"
    }
}

我们也知道我们可以更改现有数据:

请求

PUT /user/1
Accept: application/json+userdb
Content-Type: application/json+userdb

{
    "name": "Emil",
    "country": "Bhutan"
}

响应

200 OK
Content-Type: application/json+userdb

{
    "user": {
        "id": 1,
        "name": "Emil",
        "country": "Bhutan",
        "links": [
            {
                "href": "/user/1",
                "rel": "self",
                "method": "GET"
            },
            {
                "href": "/user/1",
                "rel": "edit",
                "method": "PUT"
            },
            {
                "href": "/user/1",
                "rel": "delete",
                "method": "DELETE"
            }
        ]
    },
    "links": {
       "href": "/user",
       "rel": "list",
       "method": "GET"
    }
}

请注意,我们使用不同的HTTP谓词(GET,PUT,POST,DELETE等)来操纵这些资源,而我们在客户端部分所假设的唯一知识就是我们的媒体定义。

进一步阅读:

(这个答案因缺少这一点而受到了相当多的批评。在大多数情况下,这是一个公平的批评。我最初所描述的更符合几年前当我通常实施REST时首先写下这个,而不是它的真实含义。我修改了答案以更好地代表真正的意义。)


2788
2018-03-22 19:37



不,REST不仅仅是另一个流行语。它是作为描述基于SOAP的数据交换的替代方法的手段而产生的。术语REST有助于构建有关如何传输和访问数据的讨论。 - tvanfosson
尽管如此,REST的核心(在实际应用中)是“不使用GET进行更改,使用POST / PUT / DELETE”,这是我在SOAP出现之前就已经听过(以及之后)的建议。休息 具有 一直在那里,它直到最近才获得超越“做到这一点的方式”的名称。 - Dave Sherohman
不要忘记“超文本作为应用程序状态的引擎”。 - Hank Gay
这个答案忽略了这一点。菲尔丁的论文中几乎没有提到HTTP。 - user359996
这个答案没有提到REST的目的,并使它看起来像是关于干净的URI。虽然这可能是对REST的流行看法,但是,D.Shawley和oluies的答案更准确 - 它是关于能够利用体系结构中内置的功能,如缓存,通过使用它来代替它。更漂亮的URI主要是常见的副作用。 - T.R.


RESTful编程是关于:

  • 由持久性标识符标识的资源:URI是当今无处不在的标识符选择
  • 使用一组通用动词操纵资源:HTTP方法是常见的案例 - 古老的 CreateRetrieveUpdateDelete 变 POSTGETPUT,和 DELETE。但REST不仅限于HTTP,它只是目前最常用的传输方式。
  • 为资源检索的实际表示取决于请求而不是标识符:使用Accept标头来控制是否需要XML,HTTP,甚至是表示资源的Java对象
  • 维护对象中的状态并表示表示中的状态
  • 表示资源表示中资源之间的关系:对象之间的链接直接嵌入表示中
  • 资源表示描述了如何使用表示以及在什么情况下应该以一致的方式丢弃/重新获取表示:HTTP Cache-Control头的使用

就REST的后果和整体有效性而言,最后一个可能是最重要的。总体而言,大多数RESTful讨论似乎都集中在HTTP及其在浏览器中的使用,而不是。我理解R.Fielding在描述导致HTTP的架构和决策时创造了这个术语。他的论文更多地是关于资源的体系结构和缓存能力而不是HTTP。

如果您真的对RESTful架构及其工作原理感兴趣,请阅读 他的论文 几次阅读 整件事 不只是第5章!接下来看看 为什么DNS工作。了解DNS的层次结构以及推荐的工作原理。然后阅读并考虑DNS缓存的工作原理。最后,阅读HTTP规范(RFC2616 和 RFC3040 特别是)并考虑缓存如何以及为什么以它的方式工作。最终,它只会点击。对我来说最后的启示是当我看到DNS和HTTP之间的相似之处时。在此之后,了解SOA和消息传递接口可扩展的原因开始单击。

我认为这是理解RESTful和REST的体系结构重要性和性能影响的最重要技巧 没有共享 架构是为了避免陷入技术和实现细节。专注于谁拥有资源,谁负责创建/维护它们等等。然后考虑表示,协议和技术。


500
2017-07-04 05:47



提供阅读清单的答案非常适合这个问题。 - ellisbben
感谢更新。 PUT 和 POST 不要真正与更新和创建一对一地映射。 PUT 如果客户端指示URI将是什么,则可用于创建。 POST 如果服务器正在分配新URI,则创建。 - D.Shawley
别忘了PATCH。 - epitka
URN是使用的URI urn: 方案。从概念上讲,没有区别;但是,URN确实要求您使用单独定义的方法来“定位”URN标识(命名)的资源。必须注意确保在关联命名资源及其位置时不引入隐式耦合。 - D.Shawley
@ellisbben同意。如果我理解正确,这是引起REST的论文: ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm - Philip Couling


这可能是它的样子。

创建具有三个属性的用户:

POST /user
fname=John&lname=Doe&age=25

服务器响应:

200 OK
Location: /user/123

将来,您可以检索用户信息:

GET /user/123

服务器响应:

200 OK
<fname>John</fname><lname>Doe</lname><age>25</age>

修改记录(lname 和 age 将保持不变):

PATCH /user/123
fname=Johnny

更新记录(因此 lname 和 age 将为NULL):

PUT /user/123
fname=Johnny

392
2017-11-18 20:46



对我来说,这个答案抓住了期望答案的本质。简单务实。虽然有很多其他标准,但提供的示例是一个伟大的发射台。 - CyberFonic
在最后一个例子中,@ pbreitenbach使用 PUT fname=Jonny。这会设定 lname 和 age 默认值(可能是NULL或空字符串,整数0),因为a PUT  覆盖整个资源使用来自所提供的表示的数据。这不是“更新”所暗示的, 做一个真正的更新,使用 PATCH 方法 因为这不会改变表示中未指定的字段。 - Nicholas Shanks
尼古拉斯是对的。此外,创建用户的第一个POST的URI应该被称为用户,因为 /user/1 没有意义,应该有一个列表 /users。答案应该是 201 Created 而且在那种情况下不仅仅是好的。 - DanMan
尼古拉斯和丹曼是对的。这个答案很简洁但有几个缺陷。 - leslie.zhang
这只是一个API的例子,不一定是RESTful api。 RESTful具有它所遵循的约束。客户端 - 服务器体系结构,无状态,缓存能力,分层系统,统一接口。 - Radmation


一本关于REST的好书是 实践中的REST

必读是 代表性国家转移(REST) 和 REST API必须是超文本驱动的 

参见Martin Fowlers的文章 理查森成熟度模型 (RMM)有关RESTful服务的解释。

Richardson Maturity Model

要成为RESTful,服务需要满足 超媒体作为应用状态的引擎。 (HATEOAS),也就是说,它需要在RMM中达到3级, 阅读文章 详情或 来自qcon谈话的幻灯片

HATEOAS约束是首字母缩写词   用于超媒体作为引擎   申请国。这个原则是   REST之间的关键区别   和大多数其他形式的客户端服务器   系统。

...

RESTful应用程序的客户端需要   只知道要访问的单个固定URL   它。所有未来的行动都应该是   可动态发现   超媒体链接包含在   表示资源   从该URL返回。   标准化媒体类型也是   任何人都应该理解   可能使用RESTful API的客户端。   (维基百科,自由的百科全书)

用于Web框架的REST Litmus测试 是一个类似的Web框架成熟度测试。

接近纯REST:学会爱HATEOAS 是一个很好的链接集合。

REST与公共云的SOAP 讨论了REST使用的当前级别。

REST和版本控制 讨论了可扩展性,版本控制,可演化性等。  通过可修改性


170
2018-03-22 15:20



我认为这个答案触及了理解REST的关键点:这个词是什么 代表性 意思。 1级 - 资源说的 州。 2级 - HTTP动词说的 转让 (读 更改)。 3级 - HATEOAS表示通过表示(JSON / XML / HTML返回)来驱动未来的转移,这意味着你已经知道如何用返回的信息说下一轮谈话。所以REST读取:“(代表性(状态转移))”,而不是“((代表性状态)转移)”。 - lcn
REST和POX之间的区别 - nobar


什么是REST?

REST代表Representational State Transfer。 (有时候   拼写为“ReST”。)它依赖于无状态的客户端服务器,可缓存   通信协议 - 实际上在所有情况下都是HTTP   使用协议。

REST是一种用于设计网络应用程序的架构风格。   这个想法是,而不是使用CORBA之类的复杂机制,   用于在机器之间连接的RPC或SOAP,用于制作简单的HTTP   机器之间的通话。

在许多方面,可以查看基于HTTP的万维网本身   作为基于REST的架构。 RESTful应用程序使用HTTP请求   发布数据(创建和/或更新),读取数据(例如,进行查询),   并删除数据。因此,REST对所有四个CRUD使用HTTP   (创建/读取/更新/删除)操作。

REST是RPC(Remote)等机制的轻量级替代品   过程调用)和Web服务(SOAP,WSDL等)。稍后,我们会   看看REST有多简单。

尽管很简单,但REST功能齐全;基本上就是这样   您无法在Web服务中执行任何无法使用RESTful执行的操作   建筑。 REST不是“标准”。永远不会有W3C   例如,推荐REST用于REST。虽然有REST   编程框架,使用REST非常简单,你可以   通常使用标准库功能“滚动你自己”   Perl,Java或C#。

当我试图找到休息的简单真实含义时,我发现了最好的参考之一。

http://rest.elkstein.org/


128
2018-03-22 14:53





REST使用各种HTTP方法(主要是GET / PUT / DELETE)来操作数据。

而不是使用特定的URL来删除方法(比方说, /user/123/delete),你会发送一个DELETE请求 /user/[id] 用于编辑用户的URL,用于检索发送GET请求的用户的信息 /user/[id]

例如,相反,一组URL可能看起来像下面的一些..

GET /delete_user.x?id=123
GET /user/delete
GET /new_user.x
GET /user/new
GET /user?id=1
GET /user/id/1

你使用HTTP“动词”并拥有..

GET /user/2
DELETE /user/2
PUT /user

85
2017-07-12 16:33



这是“正确使用HTTP”,这与“restful”不同(尽管它与之相关) - Julian Reschke
你也可以使用/ user / del / 2和/ user / remove / 2或...... GET / DELETE / PUT / POST只是标准化,“正确”的方式来做这些事情(正如朱利安所说,并非全部有REST) - dbr
当然,但没有理由避免它们.REST只会让你每次都重新发明轮子。对于API来说,REST很棒(一致性!),但是对于构建一个随机网站而言,我说的并不重要(它可能比它的价值更麻烦) - dbr
瓦迪姆,那简直就是RPC。使用GET修改数据也很危险,因为(除其他原因外)搜索引擎可能会抓取您的删除链接并访问它们。 - aehlke
@aehlke - 我认为真正的问题是“为什么匿名用户能够从系统中删除记录?” - Spencer Ruport


它是您的系统架构适合的编程 REST风格 罗伊菲尔丁在2004年制定 他的论文。由于这是描述网络的架构风格(或多或少),很多人对此感兴趣。

奖励答案:不会。除非您正在研究软件架构作为学术或设计Web服务,否则没有理由听到这个术语。


64
2018-03-23 17:11



但不是直截了当的......它使它变得更加复杂。 - hasen
此外,即使术语REST和RESTful现在几乎只在Web应用程序领域中使用,从技术上讲,没有什么可以将REST与HTTP联系起来。 - Hank Gay
Fielding的博客有一些很好的,更容易理解的关于REST的文章和常见的误解: roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven - aehlke
@HankGay我认为它不是更深奥的原因是大多数Web服务开发人员将REST视为对SOAP之类的替代方案的精彩简化。他们并不一定坚持让所有REST技术都正确 - 这可能会让REST狂热分子疯狂 - 但在大多数情况下,他们可能不需要担心确保他们的结果是“支持超媒体”的事情。 - moodboom


我想说RESTful编程将是关于创建遵循REST架构风格的系统(API)。

我找到了M. Elkstein博士关于REST的精彩,简短且易于理解的教程,并引用了大部分内容可以回答你的问题:

学习REST:教程

REST是一个 建筑风格 用于设计网络应用程序。   这个想法是,而不是使用CORBA之类的复杂机制,   用于在机器之间连接的RPC或SOAP,用于制作简单的HTTP   机器之间的通话。

  • 在许多方面,基于HTTP的万维网本身可以被视为基于REST的架构。

RESTful应用程序使用HTTP请求发布数据(创建和/或   更新),读取数据(例如,进行查询)和删除数据。因此,REST   对所有四个CRUD(创建/读取/更新/删除)操作使用HTTP。

我认为你不应该因为没有听到Stack Overflow之外的REST而感到愚蠢......,我会处于同样的境地!关于这个其他SO问题的答案 为什么REST现在变大了 可以缓解一些感受。


43
2017-07-25 09:05





如果我没有直接回答这个问题,我会道歉,但通过更详细的例子更容易理解这一切。由于所有的抽象和术语,Fielding不容易理解。

这里有一个相当不错的例子:

解释REST和超文本:Spam-E垃圾邮件清理机器人

更好的是,这里有一个简单示例的清晰解释(powerpoint更全面,但你可以在html版本中获得大部分内容):

http://www.xfront.com/REST.ppt 要么 http://www.xfront.com/REST.html

阅读完示例后,我可以看出为什么Ken说REST是超文本驱动的。我不确定他是对的,因为/ user / 123是一个指向资源的URI,并且我不清楚它是不是因为客户端“带外”知道它是不可靠的。

该xfront文档解释了REST和SOAP之间的区别,这也非常有用。菲尔丁说,“那是RPC。它尖叫RPC。“很明显,RPC不是RESTful,因此查看确切原因很有用。(SOAP是一种RPC。)


43
2018-03-22 16:36



很酷的链接,谢谢。我厌倦了这些REST家伙,他们说一些例子不是“REST-ful”,但后来拒绝说如何将这个例子改为REST-ful。 - coder_tim