首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

REST Service 的最佳实践,第 1 部分 重新解析 REST Service-4

REST Service 的最佳实践,第 1 部分 重新解析 REST Service-4

相比较这两种方式,根据我们的经验,第一种方式更好,URI 是一种好的实践,用来表示 resource 的各方面的信息,包括结果,版本,representation 形式,时间等等,它带来的好处是使客户端的工作大大降低,它很方便的可以在不同的应用之间共享。
那么怎么对 resource 进行下一步的操作(“manipulation”)呢? REST 对 Resource 的操作定义和 HTTP method 是对应起来的。HTTP 协议定义 GET、POST、PUT、DELETE 来表示对资源的获取、创建、更新和删除。“Manipulation of resources through representations”约束规定了 resource 的操作是通过 representation 来完成的,所以在 resource 的 representation 里面,需要包含对 resource 的操作怎么进行。APP(ATOM Publishing Protocol)提供了一个最佳实践,是用 <link> 的方式指明 Resource 响应的操作,下面是一个实例:
<link rel="edit" href="http://www.example.com/books/123456"/>
rel 定义了该 link 的 resource 和当前 resource 的关系,href 定义了 resource 的 HTTP endpoint。所以当用户想更新 id 为 123456 的 book 的价钱的时候,客户端会发一个 PUT 请求到指定的 URI,示例如清单 10 所示:
清单 10. 更新 resource 的 request 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PUT /books/123456 HTTP/1.1
Host: example.com

Reponse:
HTTP/1.1 200 OK
Date: Fri, 10 Sept 2010 17:15:33 GMT
Last-Modified: Fri, 10 Sept 2010 17:15:33 GMT

<book category="CHILDREN">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>31.99</price>
</book>




同样,客户端可以发 HTTP 请求去删除这个 book,如清单 11 所示。
清单 11. 删除 resource 示例
1
2
3
4
5
DELETE /books/123456 HTTP/1.1
Host: example.com

Reponse:
HTTP/1.1 200 OK




Self-descriptive messages
REST 接口的定义强调了自描述“Self-descriptive”性。自描述性也是为了让客户端充分的理解当前的状态,下一步的状态怎么跳转。
前面讲了 resource 的 representation,只讲述了 representation 的数据的一部分。在 representation 里面,除了包含数据部分,还包括元数据,它是用来描述数据的信息,或者是一些客户端需要知道的一些领域知识。这里以 ATOM 协议为例看看怎么在 representation 里面提供自描述的信息。清单 12 是一个 ATOM 的片段。
清单 12. 一个 ATOM 形式的 resource representation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlnss="http://a9.com/-/spec/opensearch/1.1/"
xmlns:catalog="http://www.ibm.com/opensearch/1.0">
  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 </id>
<link href="http://www.example.com/books?q=harry potter&start=0" rel="self"></link>
<link href="http://www.example.com/books?q=harry potter&start=10" rel="next"></link>
  <updated>2009-08-11T03:00:27.062Z</updated>
  <title type="text"> harry potter 相关的图书 </title>
  <os:startIndex xmlnss="http://a9.com/-/spec/opensearch/1.1/">0</os:startIndex>
  <os:itemsPerPage xmlnss="http://a9.com/-/spec/opensearch/1.1/">10</os:itemsPerPage>
  <os:totalResults xmlnss="http://a9.com/-/spec/opensearch/1.1/">10</os:totalResults>
   
<entry>
<title type="text"> Harry Potter </title>
    <id>urn:id:23-27</id>
<updated>2009-07-09T11:01:26.000Z</updated>
    <category term="harry potter"></category>
   <category term="best seller"></category>
  <category term="book"></category>
   <category term="Hyper Service"></category>
   <content type="application/xml" xmlns= ’ http://www.example.com/books ’ >
    <book category="CHILDREN">
     <title lang="en">Harry Potter</title>
     <author>J K. Rowling</author>
     <year>2005</year>
     <price>31.99</price>
            </book>
    </content>
    </entry>

</feed>




从上面的例子可以看出,除了 <content> 里面的内容是和 book 数据相关的信息以外,剩下的信息都是描述性的信息,通常包括翻页信息:一共有多少页,前后翻页的 link 是什么;分类信息,时间信息,还有一些文本信息供用户阅读。
总之,服务器端尽可能的返回详细的信息,帮助客户端理解当前的状态,以及发起下一个请求所需要的所有信息,以达到“服务器端无状态”和客户端发起“状态跳转”的目的。
Hypermedia as the engine of application state
“Hypermedia as the engine of application state”是“统一接口”的最后一个约束,也是最重要的一个约束,不幸的是, Roy 的 REST 论文中对这个约束的解释特别少,在这里,我们根据我们的经验和理解,对这个约束进行描述。这个约束其实规定的是应用系统是通过 Hypermedia 的方式在不同的状态之间跳转。这句话听起来有点拗口,还是来看一个例子吧。
提供了 REST API,以 flickr.groups.members.getList 为例来看看这个 REST API 的 ,清单 13 是一个响应示例(sample response),可以看出“members”是一个 resource,它是一系列“member”的集合,也就是说,它指向其他的 resource。
清单 13. flickr.groups.members.getList 的响应示例
1
2
3
4
5
6
7
8
9
10
11
<members page="1" pages="1" perpage="100" total="33">
<member nsid="123456@N01" username="foo" iconserver="1"
iconfarm="1" membertype="2"/>
<member nsid="118210@N07" username="kewlchops666"
iconserver="0" iconfarm="0" membertype="4"/>
<member nsid="119377@N07" username="Alpha Shanan"
iconserver="0" iconfarm="0" membertype="2"/>
<member nsid="67783977@N00" username="fakedunstanp1"
iconserver="1003" iconfarm="2" membertype="3"/>
...
</members>




如果用户还想对“Alpha Shanan”了解更多呢?这时,客户端会构建一个 HTTP request,URI 为:
1
2
http://api.flickr.com/services/rest/?
method=flickr.people.getInfo?auth_key=xxxx&user_id=119377@N07




如果系统按照这种方式运行,问题在哪呢?客户端和服务器端需要有很多的共享的知识和约定,客户端需要知道获取人员信息的 API 是 method=flickr.people.getInfo 以 user_id 作为参数。这不是 Hypermedia,同时也违背了 Roy 的关于“Hypermedia as the engine of application state”的约束,所以这个不是好的 RESTful 的实现。
Hypermedia 的实质是 hyperlink, 用 hyperlink 把这些相互依赖的 resource 联系起来,这些 hyperlink 是由服务器端生成并且在 representation 里面返回来的,包括了当前的状态集合和可能的下一步的状态集合。客户端不需要任何 domain specific 知识就能够实现状态的跳转。Hypermedia 类型的 sample response 如清单 14 所示。在清单 14 中可以看到,resource 和 resource 之间的联系通过 hyperlink 关联起来,并且在 resource 的 representation 里面表示。
清单 14. REST 风格的 flickr.groups.members.getList 的 sample response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<members page="1" pages="1" perpage="100" total="33">
<member href=" http://api.flickr.com/services/rest/?
method=flickr.people.getInfo?auth_key=xxxx&user_id=123456@N01"
username="foo" iconserver="1" iconfarm="1" membertype="2"/>
<member href=" http://api.flickr.com/services/rest/?
method=flickr.people.getInfo?auth_key=xxxx&user_id=118210@N07"
username="kewlchops666" iconserver="0" iconfarm="0" membertype="4"/>
<member href=" http://api.flickr.com/services/rest/?
method=flickr.people.getInfo?auth_key=xxxx&user_id=119377@N07"
username="Alpha Shanan" iconserver="0" iconfarm="0" membertype="2"/>
<member href=" http://api.flickr.com/services/rest/?
method=flickr.people.getInfo?auth_key=xxxx&user_id=67783977@N00"
username="fakedunstanp1" iconserver="1003" iconfarm="2" membertype="3"/>
...
</members>




通过前面关于“统一接口”的解析,我们清楚地知道,REST 风格的架构使得 web 服务的“客户端”和“服务器端”很好的分离开来。“客户端”不需要关心数据的存储,使得“客户端”的可移植性()提高了。“服务器端”不用关心用户的接口和用户的状态,所以“服务器端”将变得更加简单,而且方便的获得更好的可伸缩性(scalability)。只要保持接口的定义不变 ,“客户端”和“服务器端”可以独立的开发和演变。
返回列表