什么是RESTful编程?
RESTful编程是关于以下几点的:
- 资源由持久标识符标识: 如今,URI是最常见的标识符选择。
- 资源使用一组共同的动词进行操作: HTTP方法是最常见的情况 - "创建"、"检索"、"更新"、"删除" 变成了 "POST"、"GET"、"PUT"和"DELETE"。但REST不限于HTTP,它只是目前最常用的传输方式。
- 实际检索到的资源表示取决于请求而不是标识符: 使用Accept头来控制是否希望检索XML、HTTP,甚至表示资源的Java对象。
- 在对象中维护状态并在表示中表示状态。
- 在资源表示中表示资源之间的关系: 对象之间的链接直接嵌入在表示中。
- 资源表示描述了如何使用表示以及在什么情况下应该一致地丢弃/重新获取: 使用HTTP的Cache-Control头。
最后一点可能是关于REST的后果和整体有效性最重要的。大多数关于REST的讨论似乎都集中在HTTP及其在浏览器中的使用上。我了解到,R. Fielding在描述导致HTTP的架构和决策时创造了这个术语。他的论文更多地涉及架构和资源的可缓存性,而不仅仅是HTTP。
如果你真的对RESTful架构及其工作原理感兴趣,多读几遍他的论文,并阅读整篇论文而不仅仅是第5章!接下来了解为什么DNS工作。了解DNS的层次组织以及引用的工作原理。然后阅读并考虑DNS缓存的工作原理。最后,阅读HTTP规范(特别是RFC2616和RFC3040)并考虑缓存工作方式的原因和方法。最终,你会恍然大悟。对我来说,最后的启示是当我看到DNS和HTTP之间的相似之处时。之后,理解为什么SOA和消息传递接口是可扩展的开始变得清晰起来。
我认为理解RESTful和无共享架构的架构的重要性和性能影响的最重要的技巧是避免纠缠于技术和实现细节。集中于谁拥有资源,谁负责创建/维护资源等。然后考虑表示、协议和技术。
一个提供阅读列表的答案对于这个问题非常合适。
谢谢更新。PUT和POST并不完全对应于更新和创建。如果客户端决定URI将是什么,PUT可以用于创建。如果服务器分配新的URI,则POST会创建。
URI?有人使用URN来实现REST服务吗?
URN是使用"urn:"方案的URI。从概念上讲没有区别;然而,URN要求你有一个单独定义的方法来"定位"由URN标识(命名)的资源。在相关命名资源和其位置时,必须小心确保不引入隐式耦合。
多年来,我一直在阅读有关RESTful的内容,并在嵌入式系统中尽可能地实践RESTful原则。这个答案迄今为止是我见过的最好的。简明、准确、切中要点。非常棒!
同意。如果我理解正确,这是导致REST诞生的论文:ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
对于这一点有一个疑问:"实际检索到的资源表示取决于请求而不是标识符: 使用HTTP Accept头来控制是否希望检索XML、HTTP,甚至表示资源的Java对象" -- 这里,应该是"...是否希望检索XML、HTML,甚至表示资源的Java对象..." 我认为HTTP Accept头告诉交换的数据格式。而HTTP是RESTful Web API中使用的协议。
此外,资源操作请求应该是无状态的,并以常见的HTTP代码进行响应。
你能否替换所有“动词”的提及为“方法”?规范(如RFC2616等)中并没有使用“动词”这个术语,只有“方法”。我还要提出一个问题:方法“OPTIONS”和“HEAD”是动词吗?
PUT用于将某物放置在特定资源上,意味着用户知道要将其放置在哪里,它可以创建或更新。POST用于创建新资源,并且您希望得到一个指向该资源的链接。
"在对象中维护状态并在表示中表示状态" - 不清楚“对象”是什么?它在哪里?服务器?客户端?
另外,请参考这个链接以获取更多信息: news.ycombinator.com/item?id=3538585
RESTful编程是一种架构风格,它提倡Web应用程序应该使用最初的HTTP协议。查询应该使用GET请求,而用于更改、创建和删除的请求则应该使用PUT、POST和DELETE请求。REST支持者倾向于使用URL,但REST架构并不要求使用“pretty URLs”。带有参数的GET请求也是完全符合RESTful的。需要注意的是,GET请求不应该用于更新信息。在添加商品到购物车的例子中,使用GET请求是不合适的,因为GET请求应该是幂等的,而执行两次GET请求会导致两个商品添加到购物车中。在这种情况下,显然应该使用POST请求。因此,即使是RESTful的Web应用程序也需要使用POST请求。
RESTful编程的出现原因是为了提倡Web应用程序使用HTTP协议的原始设计,以提高应用程序的可维护性和可扩展性。解决方法是使用REST架构风格,明确规定了不同类型的HTTP请求应该用于不同类型的操作,使得应用程序的设计更加规范和易于理解。
参考链接:
- [REST的正确解释](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven)
- [S3 REST API和POST方法](https://stackoverflow.com/questions/19843480/19844272#19844272)
- [可安全和幂等的方法的列表](restapitutorial.com/lessons/idempotency.html)
- [安全和幂等方法的附加参考](w3.org/Protocols/rfc2616/rfc2616-sec9.html)
- [PUT vs. POST的讨论](https://stackoverflow.com/q/630453/1432478)
RESTful编程是指一种遵循REST原则的编程方式。REST是互联网的基本架构原则,它允许客户端(浏览器)和服务器在不需要客户端事先了解服务器和资源的情况下进行复杂的交互。REST的关键约束是服务器和客户端必须都同意使用的媒体类型,在web中,这个媒体类型就是HTML。
RESTful API不要求客户端了解API的结构,而是要求服务器提供客户端需要与服务交互所需的所有信息。HTML表单就是一个例子:服务器指定资源的位置和所需字段,浏览器在提交信息之前不知道要将信息提交到哪里,也不知道应该提交什么信息,所有这些信息都由服务器提供(这个原则被称为HATEOAS:Hypermedia As The Engine Of Application State)。
那么,这如何应用到HTTP中,以及如何在实践中实现呢?HTTP是围绕动词和资源的。GET和POST是最常见的动词,但HTTP标准定义了其他一些动词,如PUT和DELETE。这些动词根据服务器提供的指令应用于资源。
以一个用户数据库为例,该数据库由一个Web服务进行管理。该服务使用基于JSON的自定义超媒体,我们为其分配了媒体类型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"
}
]
}
从我们的媒体描述中,我们可以找到有关相关资源的信息,这些信息位于名为“links”的部分。这被称为超媒体控件。在这种情况下,我们可以从这样一个部分得知,我们可以通过对/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等)来操作这些资源,而客户端唯一需要了解的就是我们的媒体定义。
总结一下,RESTful编程是一种遵循REST原则的编程方式,它允许服务器和客户端在不需要事先了解对方的情况下进行复杂的交互。通过使用合适的HTTP动词和资源,以及提供媒体类型和超媒体控件,可以实现RESTful编程。