对REST的理解

最近才知道原来WEB Service和REST、SOAP是有区别的。这篇文章就来说下小秦对REST的理解。REST的含义可以看下下面几个链接:
链接1
链接2

重点是第二个连接中的论文。

先说说REST API的好处(REST是种架构,这里的REST API指的是HTTP协议,下文会讲到其关系):
1.WEB是REST API的一个实例,因此支持REST API的设计可以复用很多WEB的组件,比如Cache(SOAP做不到)
2.浏览器就是一个很好的client,可以方便测试
3.标准的REST API是保证无状态性的。部分操作保证幂等性和安全性。(SOAP不保证这一点)
4.面向资源,通过HTTP method对资源采取操作,有利于RBAC这类权限控制方法的实施(SOAP的权限管理和这个不一样)
5.操作语义对中间组件的可见(SOAP就不支持)
6.减少客户端和服务端的耦合性
7.简单、可伸缩,无状态(SOAP不保证每次调用都是无状态)
8.松耦合
9.HATEOAS

说实话,一开始以为HTTP协议就是用来传输网页、传输数据的,学习了REST后才知道,HTTP代表的是“超文本转换协议”,而不是“超文本传输协议”。传输对于HTTP协议来说,只是GET方法的返回罢了,对于HTTP协议来说,其还有POST、DELETE、PUT、HEAD等等几个方法,同时各种不同方法也有不同的返回值,而不仅仅只是个404。

REST在一开始提出来的时候,其目的是为了构造一个分布式系统。这个分布式系统有如下约束(或者说要求),参考论文或这个链接(http://www.infoq.com/cn/articles/understanding-restful-style):

1.客户-服务器(Client-Server)
通信只能由客户端单方面发起,表现为请求-响应的形式。

2.无状态(Stateless)
通信的会话状态(Session State)应该全部由客户端负责维护。

3.缓存(Cache)
响应内容可以在通信链的某处被缓存,以改善网络效率。

4.统一接口(Uniform Interface)
通信链的组件之间通过统一的接口相互通信,以提高交互的可见性。

5.分层系统(Layered System)
通过限制组件的行为(即,每个组件只能“看到”与其交互的紧邻层),将架构分解为若干等级的层。

6按需代码(Code-On-Demand,可选)
支持通过下载并执行一些代码(例如Java Applet、Flash或JavaScript),对客户端的功能进行扩展。

为了设计出满足上面6个条件的分布式系统,作者提出了REST这个“架构”(小秦我认为REST指的是一种分布式网络软件的架构)。架构的软件部署如下:
REST架构
在这个架构中,客户端和服务器端通过某种协议进行通信,但这种通信不一定是直接通信的,可能会有缓存或proxy。所有的通信都通过一种协议进行信息的交互,并且这种协议能够做到每次交互是无状态的,能够做到让中间层决定是否使用缓存,能够做到对于不同的层也是提供同样的接口。HTTP 1.1协议就是这么一种支持WEB这个REST架构的一种通信协议。WEB的架构一般如下:
WEB架构
可以看到,WEB就是一个REST架构的分布式系统,并且,其工作的很好。

既然知道了REST架构的要求以及部署方式,现在还需要知道的是HTTP这个协议是如何做到支持无状态、缓存和统一接口这三件事情的。作者将REST中请求的目标都抽象为资源,因此请求一个资源,很容易做到缓存和统一接口(GET一个资源那么中间层就可以考虑使用缓存,接口的话都通过URI)。对于无状态也很简单,只要每次请求都包含足够信息即可。所以,在HTTP中,每个链接地址代表的都是一个资源(比如一个页面,一张图片)。

从这里开始,我们可以看到,REST所面对的东西其实是指的资源。HTTP的几个方法,如GET、POST、DELETE等,都是对资源的一种操作,一种转换。如果有能力自己设计个协议,支持上面提出的几点要求,能做到无状态、支持缓存、CS架构、统一接口、分层,那么完全可以使用自己的协议而不是用HTTP协议。不过HTTP这么好,并且有很多现成的工具,为啥不用呢?SOAP将HTTP作为传输协议来使用,这个就是他的问题所在,其不支持上面提到的几点要求,因此如果WEB是使用SOAP来做交互协议的,那么很多cache工具都不能使用了。但是在某些系统中,SOAP是比REST有用的。

REST的最高层次是只需要访问/,就能得到所有的资源。可以参考这个链接:http://stackoverflow.com/questions/671118/what-exactly-is-restful-programming

最后来说个实际设计时候小秦遇到的一个问题,这个问题小秦也提问过,这里说下我的理解:

比如设计一个论坛系统,每个用户都可以发表评论,因此对于评论可以由如下URI:
查看所有评论:GET 127.0.0.1/users/11111/discussions
查看所有用户: GET 127.0.0.1/users
通过组合,我可以得到这个论坛的所有评论。

但还有一种方法:
查看所有评论:GET 127.0.0.1/discussions
查看某个人的评论: GET 127.0.0.1/discussions?user=11111

此时对于评论这个resource来说,就有两种URI了。小秦我的理解是应该使用第二种方法来设计REST API。原因是每个discussion都是一个对象,因此第二个更能反映真实情况,且第二种方式能让client更简单的实现其所需要的功能。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*