RESTful编程到底是什么?
什么是RESTful编程?REST是web的基本架构原则。web的惊人之处在于,客户端(浏览器)和服务器可以以复杂的方式进行交互,而客户端事先不知道服务器及其承载的资源。关键的限制是服务器和客户端必须就所使用的媒体达成一致,在web的情况下是HTML 遵循REST原则的API不要求客户机了解任何有关API结构的信息。相反,服务器需要提供客户端与服务交互所需的任何信息。HTML表单就是一个例子:服务器指定资源的位置和必需的字段浏览器事先不知道在哪里提交信息,也不知道要提交什么信息。这两种形式的信息都完全由服务器提供。(这一原则称为。) 那么,这是如何应用于HTTP的,以及如何在实践中实现它呢?HTTP以动词和资源为导向。主流用法中的两个动词是RESTful编程到底是什么?,rest,http,architecture,definition,Rest,Http,Architecture,Definition,什么是RESTful编程?REST是web的基本架构原则。web的惊人之处在于,客户端(浏览器)和服务器可以以复杂的方式进行交互,而客户端事先不知道服务器及其承载的资源。关键的限制是服务器和客户端必须就所使用的媒体达成一致,在web的情况下是HTML 遵循REST原则的API不要求客户机了解任何有关API结构的信息。相反,服务器需要提供客户端与服务交互所需的任何信息。HTML表单就是一个例子:服务器指定资源的位置和必需的字段浏览器事先不知道在哪里提交信息,也不知道要提交什么信息。这两种形式的信息
GET
和POST
,我想大家都会认识。但是,HTTP标准定义了一些其他标准,如PUT
和DELETE
。然后,根据服务器提供的说明,将这些谓词应用于资源
例如,假设我们有一个由web服务管理的用户数据库。我们的服务使用基于JSON的自定义超媒体,为此我们分配mimetypeapplication/JSON+userdb
(也可能有application/xml+userdb
和application/whatever+userdb
——可能支持多种媒体类型)。客户端和服务器都被编程为理解这种格式,但它们彼此都不了解。正如所指出的那样:
RESTAPI应该将其几乎所有的描述工作都花在
定义用于表示资源和驱动的媒体类型
应用程序状态,或在定义扩展关系名称和/或
为现有标准媒体类型启用超文本标记
对基本资源/
的请求可能会返回如下内容:
请求
GET /
Accept: application/json+userdb
GET /user
Accept: application/json+userdb
POST /user
Accept: application/json+userdb
Content-Type: application/json+userdb
{
"name": "Karl",
"country": "Austria"
}
PUT /user/1
Accept: application/json+userdb
Content-Type: application/json+userdb
{
"name": "Emil",
"country": "Bhutan"
}
响应
200 OK
Content-Type: application/json+userdb
{
"version": "1.0",
"links": [
{
"href": "/user",
"rel": "list",
"method": "GET"
},
{
"href": "/user",
"rel": "create",
"method": "POST"
}
]
}
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"
}
]
}
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"
}
}
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"
}
}
通过对媒体的描述,我们可以从“链接”部分找到相关资源的信息。这称为超媒体控件。在这种情况下,我们可以从这样一个部分看出,我们可以通过对/user
发出另一个请求来查找用户列表:
请求
GET /
Accept: application/json+userdb
GET /user
Accept: application/json+userdb
POST /user
Accept: application/json+userdb
Content-Type: application/json+userdb
{
"name": "Karl",
"country": "Austria"
}
PUT /user/1
Accept: application/json+userdb
Content-Type: application/json+userdb
{
"name": "Emil",
"country": "Bhutan"
}
响应
200 OK
Content-Type: application/json+userdb
{
"version": "1.0",
"links": [
{
"href": "/user",
"rel": "list",
"method": "GET"
},
{
"href": "/user",
"rel": "create",
"method": "POST"
}
]
}
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"
}
]
}
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"
}
}
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"
}
}
我们可以从这个反应中看出很多。例如,我们现在知道,我们可以通过POST
ing到/user
创建一个新用户:
请求
GET /
Accept: application/json+userdb
GET /user
Accept: application/json+userdb
POST /user
Accept: application/json+userdb
Content-Type: application/json+userdb
{
"name": "Karl",
"country": "Austria"
}
PUT /user/1
Accept: application/json+userdb
Content-Type: application/json+userdb
{
"name": "Emil",
"country": "Bhutan"
}
响应
200 OK
Content-Type: application/json+userdb
{
"version": "1.0",
"links": [
{
"href": "/user",
"rel": "list",
"method": "GET"
},
{
"href": "/user",
"rel": "create",
"method": "POST"
}
]
}
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"
}
]
}
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"
}
}
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"
}
}
我们还知道,我们可以更改现有数据:
请求
GET /
Accept: application/json+userdb
GET /user
Accept: application/json+userdb
POST /user
Accept: application/json+userdb
Content-Type: application/json+userdb
{
"name": "Karl",
"country": "Austria"
}
PUT /user/1
Accept: application/json+userdb
Content-Type: application/json+userdb
{
"name": "Emil",
"country": "Bhutan"
}
响应
200 OK
Content-Type: application/json+userdb
{
"version": "1.0",
"links": [
{
"href": "/user",
"rel": "list",
"method": "GET"
},
{
"href": "/user",
"rel": "create",
"method": "POST"
}
]
}
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"
}
]
}
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"
}
}
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通常是如何实现的,而不是它的真正含义。我修改了答案,以更好地代表真正的意思编程时,系统的架构符合Roy Fielding的布局。由于这是描述web的架构风格(或多或少),很多人都对它感兴趣
额外的回答:不是。除非你是作为一名学者学习软件体系结构或设计web服务,否则没有理由听过这个术语。REST使用各种HTTP方法(主要是GET/PUT/DELETE)来操作数据 您可以向
/user/[id]
URL发送删除请求,编辑用户,检索向/user/[id]
发送GET请求的用户的信息,而不是使用特定的URL来删除方法(例如,/user/123/delete
)
例如,改为一组URL,这些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
我看到很多答案都说,将关于用户123的所有信息放在资源“/user/123”是RESTful的 创造这个术语的RoyFielding说,尤其是“RESTAPI不能定义固定的资源名称或层次结构”
因此,如果您的“/user/123”路径在客户端上是硬编码的,那么它就不是真正的RESTful。HTTP的良好使用,可能,可能不是。但不是RESTful。它必须来自超文本。RESTful编程是关于:
- 由持久标识符标识的资源:URI是当今普遍存在的标识符选择
- 使用一组常见的动词操纵资源:HTTP方法是常见的情况——古老的
,Create
,Retrieve
,Update
变成Delete
,POST
,GET
,以及PUT
。但REST并不限于HTTP,它只是最常见的方法现在是最常用的交通工具Delete
- 为资源检索到的实际表示形式取决于请求,而不是标识符:使用Accept标头来控制是否需要表示资源的XML、HTTP甚至Java对象
- 在对象中维护状态并在表示中表示状态