RESTful 编程到底是什么?

RESTful 编程到底是什么?

答案

REST是 Web 的基础架构原理。 Web 的惊人之处在于,客户端(浏览器)和服务器可以以复杂的方式进行交互,而无需客户端事先了解服务器及其托管的资源。关键约束是服务器和客户端都必须在所使用的媒体上达成共识,在网络上为HTML

遵循REST原理的 API 不需要客户端了解有关 API 结构的任何信息。相反,服务器需要提供客户端与服务交互所需的任何信息。 HTML 表单就是这样的一个示例:服务器指定资源的位置和必填字段。 浏览器不预先知道在哪里提交信息,也不知道要提交什么信息。两种形式的信息都完全由服务器提供。 (该原理称为HATEOAS :作为应用程序状态引擎的超媒体 。)

那么,这如何适用于HTTP以及如何在实践中实现? HTTP 围绕动词和资源。主流用法中的两个动词是GETPOST ,我想每个人都会意识到。但是,HTTP 标准定义了其他几种,例如PUTDELETE 。然后根据服务器提供的指示将这些动词应用于资源。

例如,假设我们有一个由 Web 服务管理的用户数据库。我们的服务使用基于 JSON 的自定义超媒体,为此我们为其分配了 mimetype application/json+userdb (可能还有一个application/xml+userdbapplication/whatever+userdb可能支持许多媒体类型)。客户端和服务器都已被编程为可以理解这种格式,但是它们彼此之间一无所知。正如Roy Fielding指出的那样:

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创建一个新/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 动词( GETPUTPOSTDELETE等)来操纵这些资源,并且我们假定客户端唯一的知识就是媒体定义。

进一步阅读:

(这个答案因缺少要点而受到了很多批评。大多数情况下,这是一个合理的批评。我最初描述的内容与几年前我通常使用 REST 的方式更加一致。首先是写这个,而不是真正的意思。我已经修改了答案,以更好地代表真实的意思。)

一种称为REST(代表性状态转移)架构风格主张 Web 应用程序应使用最初设想的 HTTP。查找应使用GET请求。 PUTPOSTDELETE请求应分别用于突变,创建和删除

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 请求共享。

这摘自 David M. Geary 的出色著作《 Core JavaServer Faces 》。

RESTful 编程是关于:

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

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

如果你是在一个 RESTful 架构是真正感兴趣的,为什么它的作品,读了他的论文几次,阅读整个事情不只是第 5 章!接下来研究DNS 为什么起作用 。阅读有关 DNS 的层次结构以及引用如何工作的信息。然后阅读并考虑 DNS 缓存如何工作。最后,阅读 HTTP 规范(特别是RFC2616RFC3040 ),并考虑缓存如何以及为什么以这种方式工作。最终,它只会单击。对我来说,最后的启示是当我看到 DNS 和 HTTP 之间的相似之处时。在此之后,开始理解为什么 SOA 和消息传递接口是可伸缩的。

我认为理解 RESTful 和无共享架构的架构重要性和性能含义的最重要技巧是避免陷入技术和实现细节上。专注于谁拥有资源,谁负责创建 / 维护资源,等等。然后考虑表示形式,协议和技术。

这就是它的样子。

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

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>

修改记录( lnameage将保持不变):

PATCH /user/123
fname=Johnny

要更新记录(因此, lnameage将为 NULL):

PUT /user/123
fname=Johnny

关于 REST 的一本很棒的书是REST in Practice

必须读取的是代表性状态传输(REST),并且REST API 必须是超文本驱动的

有关什么是 RESTful 服务的说明,请参阅 Martin Fowlers 的Richardson 成熟度模型 (RMM)。

理查森成熟度模型

为了实现 RESTful 服务,需要将超媒体作为应用程序状态引擎。 (HATEOAS) ,也就是说,它需要达到 RMM 中的第 3 级,请阅读文章以了解详细信息或qcon 演讲中幻灯片

HATEOAS 约束是 Hypermedia 作为应用程序状态引擎的首字母缩写。该原理是 REST 与大多数其他形式的客户端服务器系统之间的主要区别。

...

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

针对 Web 框架的 REST Litmus 测试是针对 Web 框架的类似成熟度测试。

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

REST 与 SOAP for Public Cloud讨论了 REST 使用的当前级别。

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

什么是 REST?

REST 代表代表性状态转移。 (它有时被拼写为 “ReST”。)它依赖于无状态,客户端 - 服务器,可缓存的通信协议 - 几乎在所有情况下,都使用 HTTP 协议。

REST 是用于设计网络应用程序的体系结构样式。这个想法是,与其使用诸如 CORBA,RPC 或 SOAP 之类的复杂机制在计算机之间进行连接,不如使用简单的 HTTP 在计算机之间进行调用。

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

REST 是 RPC(远程过程调用)和 Web 服务(SOAP,WSDL 等)之类的机制的轻量级替代。稍后,我们将了解 REST 更简单。

尽管简单,但 REST 具有完整的功能。基本上,在 Web 服务中您无法做的事是 RESTful 架构无法完成的。 REST 不是 “标准”。例如,永远不会有针对 REST 的 W3C 建议。尽管存在 REST 编程框架,但使用 REST 是如此简单,以至于您经常可以使用 Perl,Java 或 C#等语言的标准库功能来 “自己动手”。

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

http://rest.elkstein.org/

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

您无需使用特定的 URL 来删除方法(例如/user/123/delete ),而是将 DELETE 请求发送到/user/[id] URL,以编辑用户,检索有关您发送的用户的信息对/user/[id]的 GET 请求

例如,取而代之的是一组可能类似于以下内容的 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

在程序设计中,您的系统架构适合 Roy Fielding 在其论文中提出REST 风格 。由于这是描述 Web 的建筑风格(或多或少),因此许多人对此感兴趣。

奖励答案:否。除非您以软件学者的身份学习或设计 Web 服务,否则确实没有理由听到这个词。

我要说的是 RESTful 编程是关于创建遵循 REST 体系结构样式的系统(API)。

我发现 M. Elkstein 博士撰写的这个关于 REST 的奇妙,简短且易于理解的教程,并引用了将在很大程度上回答您的问题的基本部分:

学习 REST:教程

REST 是用于设计网络应用程序的体系结构样式 。这个想法是,与其使用诸如 CORBA,RPC 或 SOAP 之类的复杂机制在计算机之间进行连接,不如使用简单的 HTTP 在计算机之间进行调用。

  • 在许多方面,基于 HTTP 的万维网本身都可以视为基于 REST 的体系结构。

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

我不认为您没有在 Stack Overflow 之外没有听说过 REST 会感到愚蠢…… 我会处于同样的情况!关于REST 为什么现在变得如此庞大的另一个 SO 问题的答案可能会缓解一些感觉。

抱歉,如果我没有直接回答问题,请通过更详细的示例更轻松地理解所有内容。由于所有的抽象和术语,对字段的理解并不容易。

这里有一个很好的例子:

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

甚至更好的是,这里有一个简单示例的简洁说明(powerpoint 更为全面,但是您可以在 html 版本中获得大部分):

http://www.xfront.com/REST.ppthttp://www.xfront.com/REST.html

阅读示例之后,我可以看到 Ken 为什么说 REST 是超文本驱动的。我实际上不确定他是否正确,因为 / user / 123 是指向资源的 URI,而且我不清楚它是否是非 RESTful 的,仅仅是因为客户端 “带外” 知道它。

该 xfront 文档解释了 REST 和 SOAP 之间的区别,这确实也很有帮助。当 Fielding 说 “ 那是 RPC。它尖叫着 RPC。 ” 时,很明显 RPC 不是 RESTful 的,因此了解其确切原因很有用。 (SOAP 是一种 RPC。)