怎样用通俗的语言解释REST,以及RESTful?
楼上已经有人一一列举解释了REST的约束(Client-Server、Stateless、Cache、Uniform Interface、Layered System、Code-on-Demand),我就不具体具体展开约束这一个块了,准备用一个简单的列子来描述什么是Representation,什么是State,以及什么是Representation State Transfer。
例如我订阅了一个人的博客,想要获取他发表的所有文章(这里『他发表的所有文章』就是一个资源Resource)。于是我就向他的服务发出请求,说『我要获取你发表的所有文章,最好是atom格式的』,这时候服务器向你返回了atom格式的文章列表第一页(这里『atom格式的文章列表』就是表征Representation)。
你看到了第一页的页尾,想要看第二页,这时候有趣的事情就来了。如果服务器记录了应用的状态(stateful),那么你只要向服务询问『我要看下一页』,那么服务器自然就会返回第二页。类似的,如果你当前在第二页,想服务器请求『我要看下一页』,那就会得到第三页。但是REST的服务器恰恰是无状态的(stateless),服务器并没有保持你当前处于第几页,也就无法响应『下一页』这种具有状态性质的请求。因此客户端需要去维护当前应用的状态(application state),也就是『如何获取下一页资源』。当然,『下一页资源』的业务逻辑必然是由服务端来提供。服务器在文章列表的atom表征中加入一个URI超链接(hyper link),指向下一页文章列表对应的资源。客户端就可以使用统一接口(Uniform Interface)的方式,从这个URI中获取到他想要的下一页文章列表资源。上面的『能够进入下一页』就是应用的状态(State)。服务器把『能够进入下一页』这个状态以atom表征形式传输(Transfer)给客户端就是表征状态传输(REpresentational State Transfer)这个概念。
举个具体API的例子:
请求:
GET /posts HTTP/1.1
Accept: application/atom+xml
响应:
HTTP/1.1 200 OK
Content-Type: application/atom+xml
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Posts</title>
<link href="http://example.org/posts" rel="self" />
<link href="http://example.org/posts?pn=2" rel="next" />
<id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
<updated>2003-12-13T18:30:02Z</updated>
<entry>
<title>Post XXX</title>
<link href="http://example.org/post-xxx" />
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>This is the post content.</p>
</div>
</content>
</entry>
<entry>...</entry>
</feed>
注意上面atom格式中的多个<link>元素,它们分别定义了当前状态下合法的状态转移。
例如,这是一个指向自己的链接,其中rel属性指定了状态转移的关系为自身。
<link href="http://example.org/posts" rel="self" />
这是下一页的链接,
<link href="http://example.org/posts?pn=2" rel="next" />
如果当前不是第一页的话,就会有类似如下的链接来表示上一页,
<link href="http://example.org/posts?pn=2" rel="prev" />
而这个是某一篇文章的链接,
<link href="http://example.org/post-xxx" />
总结一下,就是:
- 服务器生成包含状态转移的表征数据,用来响应客户端对于一个资源的请求;
- 客户端借助这份表征数据,记录了当前的应用状态以及对应可转移状态的方式。
当然,为了要实现这一系列的功能,一个不可或缺的东西就是超文本(hypertext)或者说超媒体类型(hypermedia type)。这绝对不是一个简简单单的媒体类型(例如,JSON属性列表)可以做到的。(参考:
REST APIs must be hypertext-driven)
因此,像下面这种API,
1、获取文章
请求:
GET /blog/post/{postId} HTTP/1.1
响应:
HTTP/1.1 200 OK
{
"title": "foobar",
"content": "foobar",
"comments": ["", "", ""]
}
2、发布文章
请求:
POST /blog/post HTTP/1.1
{
"title": "foobar",
"content": "foobar",
"comments": ["", "", ""]
}
响应:
HTTP/1.1 201 CREATED
绝对不是RESTful!
绝对不是RESTful!
绝对不是RESTful!
(重要的事情要说三遍)
=====2015-06-19更新=====
在
REST in Practice (豆瓣)书中介绍了一种叫做
Richardson Maturity Model的Web服务成熟度模型。而上面的这种API属于其第二层HTTP Verbs,RESTful的API属于第三层Hypermedia Controls。相比第二层,第三层的Web服务具有一个很明显的优势,客户端与服务端交互解耦。服务端可以仅仅提供单一的入口,客户端只要依次“遍历”超链接,就可以完成对应的合法业务逻辑。当资源的转换规则发送变化时(如某一页由于历史文章被删除了而没有下一页,又或者某篇文章转储在了其他网站上),客户端不需要作额外的更新升级,只需要升级服务端返回的超链接即可。
=====华丽的分割线=====
最后发几个链接(论文、一本介绍很详细的好书以及一个RESTful API)供大家参考