菜鸟笔记
提升您的技术认知

RESTfull 接口规范理解

RESTfull接口规范理解

RESTfull = Representational State Transfer 即表现层状态转移 加 ful (即形容词后缀) 则表示是形容词性的

而要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组,直译过来就是「表现层状态转化」,其实它省略了主语。「表现层」其实指的是「资源」的「表现层」,所以通俗来讲就是:资源在网络中以某种表现形式进行状态转移。分解开来:

  • Resource:资源,即数据。比如usenames/users/friends/menu/order等;
  • Representational:某种表现形式,比如用JSON,XML,JPEG等;
  • State Transfer:状态变化。通过HTTP动词实现。

然后再来理解一个具体的RESTful架构——面向资源的架构(Resource-Oriented Architecture,ROA):

  • 资源是由URI来指定。所谓「上网」,就是与互联网上一系列的「资源」互动,调用它的URI。
  • 对资源的操作包括获取、创建、修改和删除资源,这些操作正好对应HTTP协议提供的
  • get(获取网络中某个地址的资源),
    • post(创建资源也叫更新资源),
    • put(更新资源),
    • patch(更新网络资源),
    • delete(删除网络资源)
    • 最常见的就是get和post请求
    • 通过操作资源的表现形式来操作资源。具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定。
  • 资源的表现形式则是XML或者HTML,取决于读者是机器还是人,是消费web服务的客户软件还是web浏览器。当然也可以是任何其他的格式。

应用于Web服务,符合REST设计风格的Web API称为RESTful API。它从以下三个方面资源进行定义:

  • 直观简短的资源地址:URI,比如:http://example.com/resources/;每一个URI代表一种资源;
  • 传输的资源:Web服务接受与返回的互联网媒体类型,比如:JSON,XML,YAML等。
  • 对资源的操作:Web服务在该资源上所支持的一系列请求方法(比如:POST,GET,PUT或DELETE)。

HTTP请求方法在RESTful API中的典型应用:

资源 GET PUT POST DELETE
一组资源的URI,比如http://example.com/resources/ 列出URI,以及该资源组中每个资源的详细信息(后者可选)。 使用给定的一组资源替换当前整组资源。 在本组资源中创建/追加一个新的资源。该操作往往返回新资源的URL。 删除整组资源。
单个资源的URI,比如http://example.com/resources/142 获取指定的资源的详细信息,格式可以自选一个合适的网络媒体类型(比如:XML、JSON等) 替换/创建指定的资源。并将其追加到相应的资源组中。 把指定的资源当做一个资源组,并在其下创建/追加一个新的元素,使其隶属于当前资源。 删除指定的元素。

REST的误解

现在看来,REST在2000年那个时代,确实是超前于时代的。Web开发者社区对于HTTP的设计意图存在着大量的误解,由此导致了对于HTTP的大量低效率的误用。这个情况持续一直到2005年Web 2.0的崛起。那个时候,DCOM、EJB、SOAP/WSDL这些DO风格的架构由于难以满足互联网环境对分布式应用架构设计的约束,与Web自身的架构风格REST相冲突,很难融入到Web之中。所谓的「Web Services」,其实除了将HTTP作为底层的传输协议外,跟(互联网环境中的)真正的Web没有什么关系。

而随着Ruby on Rails这个著名的Web开发框架开始大力支持REST开发之后,一线的Web开发者才真正接触到了REST。然而Rails所支持的REST开发将对资源的操作局限于CRUD(创建、获取、修改、删除)的语义(即,将对资源的CRUD操作映射到 GET/POST/PUT/DELETE四个HTTP方法),这其实是收窄了REST的适用范围。其他编程语言的Web开发框架(例如Java语言的 Struts、Spring mvC等等)也紧接着模仿了Rails的方式开始支持REST开发,然而这更加导致了一线的Web开发者误以为:REST开发就是 通过GET/POST/PUT/DELETE四个HTTP方法对资源执行CRUD操作。甚至还有很多仅仅使用了HTTP,而没有使用SOAP的Web服 务API,都自称是REST风格(RESTful)的API。

对于什么才是真正的REST风格的误解是如此之多,而将REST作为一个便于营销的 buzzword的挂羊头卖狗肉者也是如此之多,以至于REST的创造者Fielding终于忍无可忍了。2008年10月Fielding写了一篇博 客,做出了一个非常明确的断言:REST APIs must be hypertext-driven!(REST API必须是超文本驱动的!)超文本驱动这个理念变成了一个缩写词HATEOAS,这个缩写词来自于当初Fielding博士论文中的一句话: hypermedia as the engine of application state(将超媒体作为应用状态的引擎)。其实超文本驱动(Hypertext Driven)的理念才是REST架构风格最核心的理念,也是REST风格的架构达到松耦合目标的根本原因。

REST设计进阶

当谈及REST成熟度时,一些人常常会引用Richardson所提出来的REST成熟度模型(Maturity Model),并视之为正确的度量方法。

1.在架构中引入资源(Resource)的概念。

大多数WS-*服务和POX都只是使用一个URI作为一个服务端口,也只使用一个HTTP方法传输数据。这种做法相当于把HTTP这个应用层协议降级为传输层协议用,《REST实战》也一再强调HTTP是一种应用协议而不是传输协议。再好一点就是使用多个URI,然而不同的URI只是作为不同的调用入口,与此同时只使用同一个HTTP方法传输数据。最常见的错误就是在URI中包含动词,比如URI http://example.com/getOrder?orderId=1234,其实「资源」表示一种实体,所以应该是名词,动词应该放在HTTP协议中。而与此同时URI也有可能破坏HTTP GET的安全性和幕等性,比如某个客户端在http://example.com/updateOrder?id=1234&coffee=latte上执行GET(而不是POST),就能创建一笔新的咖啡订单(一个资源),按理来说GET请求不能改变服务的任何状态。

2.每一个URI代表一种资源,支持HTTP动词(即get,post,put,delete)。

此时使用多个URI的话,需要让不同的URI代表不同的资源(注意多个URI可能指向同一个Resource,而一个URI不能指向不同Resource。),同时使用多个HTTP方法操作这些资源,例如使用POST/GET/PUT/DELET分别进行CRUD操作。这时候HTTP头和有效载荷都包含业务逻辑,例如HTTP方法对应CRUD操作,HTTP状态码对应操作结果的状态。我们现在看到的大多数所谓RESTful API做到的也就是这个级别。《REST实战》的译者也谈到:悟性差的人,理解到CRUD式Web服务就满足了。而悟性好的人,可以彻底理解超文本驱动,甚至是与REST关系密切的语义网,最终达到 REST开发的最高境界。