怎样用通俗的语言解释REST,以及RESTful?

看了网上好多对REST的介绍,非常理论,让人很难耐着性子看完。即使看完了,还是会云里雾里,不知所云。 了解了什么是REST,我们再看看RESTful的…
关注者
4,830
被浏览
3,060,770
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

楼上已经有人一一列举解释了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" />

总结一下,就是:

  1. 服务器生成包含状态转移的表征数据,用来响应客户端对于一个资源的请求;
  2. 客户端借助这份表征数据,记录了当前的应用状态以及对应可转移状态的方式。

当然,为了要实现这一系列的功能,一个不可或缺的东西就是超文本(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)供大家参考

  1. Fielding Dissertation: CHAPTER 5: Representational State Transfer (REST)
  2. REST in Practice (豆瓣)
  3. Atom (standard)