RESTful编程究竟是什么?

RESTful编程究竟是什么?


一种名为REST(Representational State Transfer)架构风格主张网络应用程序应该像最初设想的那样使用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出版的优秀着作“核心JavaServer面向书”中找到的。


REST是Web的基础架构原则。 令人惊讶的事情是,客户端(浏览器)和服务器可以以复杂的方式进行交互,而客户端事先不了解服务器及其托管的资源。 关键的约束是服务器和客户端必须同意使用的媒体,在网络中是HTML。

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

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

例如,我们假设我们有一个由Web服务管理的用户数据库。 我们的服务使用基于JSON的定制超媒体,为此我们分配了mimetype application / json + userdb(可能还有一个application / xml + userdb和application / whatever + 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"
        }
    ]
}

我们可以从这个回应中看出很多。 例如,我们现在知道我们可以通过发布到/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动词(GET,PUT,POST,DELETE等)来操纵这些资源,并且我们在客户端部分中唯一的知识就是我们的媒体定义。

进一步阅读:

  • 在这个页面上有很多更好的答案。
  • 我如何向我的妻子解释REST。
  • 我如何向我的妻子解释REST。
  • 马丁福勒的想法
  • Paypal的API具有超媒体控件
  • (这个答案由于缺少了这个观点而受到了相当多的批评,这在很大程度上是一个公平的批评,我最初描述的更多的是与几年前通常实现REST的方式一致,首先写这个,而不是它的真正含义,我已经修改了答案以更好地表达真正的意思。)


    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规范(特别是RFC2616和RFC3040),并考虑缓存如何以及为什么如此工作。 最终,它只会点击。 对我来说最后的启示是当我看到DNS和HTTP之间的相似性时。 在此之后,了解为什么SOA和消息传递接口可扩展性开始点击。

    我认为理解RESTful和Shared Nothing体系结构的体系结构重要性和性能影响的最重要技巧是避免挂上技术和实现细节。 集中力量谁拥有资源,谁负责创建/维护资源等。然后考虑表示,协议和技术。

    链接地址: http://www.djcxy.com/p/199.html

    上一篇: What exactly is RESTful programming?

    下一篇: Setting "checked" for a checkbox with jQuery?