RESTful编程究竟是什么?
RESTful编程究竟是什么?
- REST代表Representational State Transfer。(它有时拼写为“ReST”。)它依赖于无状态,客户端 - 服务器,可缓存的通信协议 - 并且几乎在所有情况下都使用HTTP协议。
- REST是一种用于设计网络应用程序的架构风格。我们的想法是,不是使用CORBA,RPC或SOAP等复杂机制来连接机器,而是使用简单的HTTP在机器之间进行调用。
- 在许多方面,基于HTTP的万维网本身可以被视为基于REST的架构。RESTful应用程序使用HTTP请求发布数据(创建和/或更新),读取数据(例如,进行查询)和删除数据。因此,REST对所有四个CRUD(创建/读取/更新/删除)操作使用HTTP。
- REST是RPC(远程过程调用)和Web服务(SOAP,WSDL等)机制的轻量级替代方法。稍后,我们将看到REST更简单。
- 尽管简单,但REST功能齐全; 在Web服务中基本上没有什么可以用RESTful架构完成的。REST不是“标准”。例如,REST永远不会有W3C推荐。虽然有REST编程框架,但使用REST非常简单,您可以经常使用Perl,Java或C#等语言中的标准库功能“自己动手”。
RESTful编程是关于:
- 由持久性标识符标识的资源:URI是当今无处不在的标识符选择
- 资源使用一组共同的动词被操纵:HTTP方法是常见的情况-古老Create,Retrieve,Update,Delete变POST,GET,PUT,和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和Shared Nothing架构的体系结构重要性和性能影响的最重要技巧是避免对技术和实现细节感到困惑。专注于谁拥有资源,谁负责创建/维护它们等等。然后考虑表示,协议和技术。
称为REST(Representational State Transfer)的架构风格提倡Web应用程序应该像最初设想的那样使用HTTP 。查找应该使用GET请求。PUT,POST,DELETE请求应分别用于转变,创建和删除(mutation, creation, and deletion)。
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请求份额。
- REST是Web的基础架构原则。关于Web的惊人之处在于,客户端(浏览器)和服务器可以以复杂的方式进行交互,而客户端无需事先了解服务器及其承载的资源。关键的限制是服务器和客户端必须同意所使用的媒体,在网络的情况下是HTML。
- 遵循REST原则的API 不要求客户端了解有关API结构的任何信息。相反,服务器需要提供客户端与服务交互所需的任何信息。一个HTML表格是这样一个例子:服务器指定资源和所需的字段的位置。浏览器事先不知道提交信息的位置,并且事先不知道要提交哪些信息。两种形式的信息完全由服务器提供。(这个原则被称为HATEOAS:超媒体作为应用程序状态的引擎。)
- 那么,这如何应用于HTTP,以及如何在实践中实现?HTTP围绕动词和资源。主流使用的两个动词是GET和POST,我认为每个人都会认识到。但是,HTTP标准定义了其他几个,例如PUT和DELETE。然后根据服务器提供的指令将这些动词应用于资源。
例如,假设我们有一个由Web服务管理的用户数据库。我们的服务使用基于JSON的自定义超媒体,为此我们指定的MIME类型application/json+userdb(也有可能是一个application/xml+userdb和application/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:
请求
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等)来操纵这些资源,我们假设一客户端的部分仅有知识是我们媒体的定义。