RESTful Web

本文是Horizon第二次线下活动中“RESTful Web”讲题的总结,由PengEdy整理。前端

REST的全称是Representational State Transfer,可译为“表征状态转移”,是Roy Fielding博士在2000年他的博士论文中提出的一种软件架构风格。目前,在三中主流的Web服务实现方式中,与SOA和RPC相比,REST的实现更为简洁,于是获得愈来愈多的商业公司和开发者的青睐。git

本文将简单介绍给读者,如何理解REST、以及举例说明在开发场景的简单应用。程序员

REST从哪里来?

在理解REST以前,先要对Web和Web Service有一个简单的认识。编程

一切还要从互联网诞生提及。互联网从诞生至今,经历了几个发展阶段:浏览器

  • 阶段一:静态内容阶段缓存

    互联网自己是为欧美各高校/研究院共享信息而诞生的,在最初的那个年代,能访问到的互联网内容全都是文本内容(不少是于科研有关的论文、资料),所谓的Web服务器更像是一台支持解析超文本的文件共享服务器。安全

  • 阶段二:CGI程序阶段服务器

    后来人们想在Web上加入更多的功能,而非原先简单的超文本解析。这就须要Web服务器提供可用的API,经过程序与客户端进行通讯,达到内容交互的做用。服务器与客户端程序的通讯由CGI(通用网关接口)协议来完成,而这些用于通讯的程序就叫作CGI程序。网络

  • 阶段三:脚本语言阶段session

    CGI程序有相对较高的安全隐患和开发难度。后来,在服务器端就出现了PHP、ASP、JSP等支持session的脚本语言,浏览器端也诞生了JavaScript、Java Applet,这大大下降了Web开发的难度,而互联网上的内容与交互形式也变得更为丰富。

  • 阶段四:Thin Client App阶段

    脚本语言易于开发,但大量的堆积却不利于项目的维护,因此就有人提出了MVC开发模式,也就渐渐诞生了各种MVC开发框架。同时,也诞生了独立于Web服务器的应用服务器,这就为瘦客户端应用提供了有力的发展条件。在这个阶段里,瘦客户端再也不简单的解析HTML、执行JavaScript,而是单独执行其余的程序代码,从而提供了极为丰富的人机交互方式。互联网也变得更加精彩。

  • 阶段五:Rich Internet App阶段

    层出不穷的瘦客户端技术令开发者头晕目眩,而这时传统的Web技术有了新的发展,给开发者提供了互联网内容和交互形式均可兼得的选择。这期间,以JavaScript为核心的前端技术高速发展,诞生了Ajax、jQuery、ExtJs等模式与框架。这些技术一直到如今都煊赫一时。

  • 阶段六:Mobi App阶段

    iOS的诞生使移动互联网爆发性增加,后来也有Android和Windows Phone加入,而从前的前端技术也同时顾及桌面端和移动端。原生移动平台开发很受欢迎的同时,基于HTML5的开发技术也变得很流行。

从这个过程来看,Web变得愈来愈复杂;为了支持这样庞大的互联网,背后的技术也在不断更新。当CGI乃至服务器端脚本语言出现后,HTTP/1.0便没法知足Web开发的要求,HTTP/1.1应运而生,其做者之一的Roy Fielding博士在HTTP/1.1的基础上推导出了一种全新的软件架构风格,也就是REST。

说到REST,就必须先对Web Service有一个基本的认识。

Web服务,直观的认识能够是“万维网上的一套消息传递机制”;实际上,W3C组织给出了精准的定义:Web服务应带是一个软件系统,用以支持网络间不一样机器的互动操做,网络服务一般是由许多API组成,它们经过网络来执行客户提交的各类请求。

看过这个较为抽象的定义后,若是感受吃不消,能够结合Web服务的使用方式来进一步理解。

Web服务有三种广泛的实现方式,分别是:RPC,SOA,REST。

  • 远程过程调用(RPC)

    这是一种早期的Web服务实现方式,最容易理解,要求Web服务提供一个分布式函数或方法接口供用户调用。就比如把一套系统的函数、方法(包含参数)提供给开发者(这样作同时也会把部分信息暴露在开放的互联网上)。
    这里给出一组例子,能够感觉一下。

    Server端

    getUser(id)
    addUser(id, name)
    removeUser(id)
    updateUser(id, attr)
    getLocation(id)
    addLocation(id, Px, Py)
    removeLocation(id)
    updateLocation(id, Px, Py)

    Client端

    exampleAppObject = new ExampleApp("example.com:1234")
    exampleAppObject.getUser(id)

    这样作的弊端在于耦合性强和安全性差。当一套系统变得庞大时,组织合理的函数、方法接口将会变得很是繁琐;并且接口和程序语言有必定的关联,这样也限制了开发者。

  • 服务导向架构(SOA)

    如今,业界关注的重点是听从服务导向架构(Service-oriented Architecure)来构建的Web服务。在这种架构中,通信由消息驱动,而不是再由某个具体的动做(函数或方法调用)来实现。这种方式与RPC的最大区别是,更加关注如何去链接服务,而非关心特定细节的实现。关于SOA的更详细的资料能够查阅互联网。

  • 表征状态转移(REST)

    表征状态转移类型的Web服务相似HTTP或其余协议,它们以资源为核心,把接口限定在一组广为人知的标准动做中(如GET, PUT, DELETE等),以供调用。这类Web服务与前面两个相比,更加关注资源自己,而非消息或动做。
    下面再给出一组例子。

    Server端

    http://example.com/users/
    http://example.com/users/{user}
    http://example.com/findUserForm
    http://example.com/locations
    http://example.con/locations/{location}
    http://example.com/findLocationForm

    Client端

    userResource = new Resource("http://example.com:1234"")
    userResource.get(:id)

    显然,这种Web服务的方式并不受限于编程语言种类,组织庞大的URI也不是很繁琐,并且以资源为核心,以HTTP协议为基础,更便于在互联网上传播。
    因此,如今的互联网就是由各个Web服务构成的,从程序的角度来看,好像就是这样。

但做为普通网民,真的难以理解上面讨论的内容,由于他们才无论什么RPC/SOA/REST,他们只关心互联网的内容。因此,咱们能够拓宽对“Web服务”的理解,把Web服务看作是两部分:
* 面向人类用户的Web服务
也就是咱们打开浏览器、App所访问的Web内容。
* 面向程序/程序员的Web服务

如上所说的一套软件系统,最关键的是那组API。

因此,互联网仍是由各种Web服务组成的,这就又回到了RESTful Web的话题上。

以上,能够认为:RESTful Web就是以HTTP/1.1为基础,以资源为核心提供的现代Web服务,而“表征状态转移”就做为一种架构风格(或规范)存在,而非业界标准。

怎样才能REST?

前面说的网站、Web服务,其实都是存在于生产环境中的分布式Web系统。因此要想作到REST,咱们能够假象有一个“初始化”的Web分布式系统,给它加上约束条件,使之成为RESTful的系统。

REST架构风格中最重要的架构约束有6个:

  • 客户-服务器

    image

    由客户端发出“请求”,做为通讯的开始,服务器进行“响应”。

  • 无状态

    image

    仅由客户端负责维护通讯的会话状态

  • 缓存

    image

    响应的内容应该能够在通讯链的某个环节被缓存,以改善网络效率。

  • 统一接口

    image

    “客户端-服务器”通讯链组件之间应经过统一的软件接口来实现通讯,从而提升交互的可见性。

  • 分层系统

    image

    限制各组件的行为,实现通讯链上下游分层。

  • 按需代码

    image

    支持下载并执行一些代码(如JavaScript),对客户端功能进行扩展。

这其中,第六个约束是可选特性,也就是说仅符合前五个约束的Web分布式系统也能够看作是知足REST设计风格的。

可是,究竟怎样才能作到RESTful?

对于软件架构师,能够顺着上面的思路,最终能推导出一套知足REST的软件系统;而对于程序员,须要掌握符合REST规范的编程方法,不管是否使用支持REST的开发框架。

规范使用HTTP动词

HTTP/1.1规范规定了八个动词:OPTION, HEAD, GET, POST, PUT, DELETE, TRACE, CONNECT,分别表明了不一样的语义,其中GET, PUT, POST, DELETE就是CRUD的语义化动词,在开发Web系统中很是经常使用。

强调规范使用这些动词,是由于有不规范的状况出现。好比GET,做为一个安全动词,本来是用于发出查找请求。下面有两个很差的例子:

# Add cart
GET /add_cart?pid=1234 HTTP/1.1
Host: www.example.org

# Delete note
GET /notes/delete?id=1234 HTTP/1.1
Host: www.example.org

原本是用于请求查询的报文却在请求增长/减小资源。这样写的程序能够执行,但有很是大的隐患,有可能在未知的状况下形成数据的大量变更,好比一些缓存程序或恶意攻击。

合理命名资源

资源能够看作是一个Web系统的核心,由于不论业务逻辑怎么复杂,都是对数据进行增删改查。但资源不一样于数据,资源要有名称,并且是能够在万维网上能够定位到资源自己的名称——也就是URI(Uniform Resource Identifier)。因此资源命名就尤其重要,以知足易于编程和用户可读为标准。看下面这些例子,就能体会到。

POST   http://example.com/customers
GET    http://example.com/customers/123
DELETE http://example.com/products/123
PUT    http://example.com/customers/123/orders/45

真实的互联网还有更多形象的例子,它们那样良好的命名设计使得不管是普通用户仍是开发人员都能更方便地在网上完成相关业务,这也是REST优点的一点体现。

利用HTTP响应码指示状态

状态响应码是HTTP协议中规定的一部分。协议中规定了不少组数字,用来表示网络中可能发生的最多见的状况。若是须要开发Web系统的API,那么就须要按照HTTP报文的要求,为响应报文中提供准确的响应代码,以区分相关请求的执行状态。

好比在客户端执行了某个GET请求,API一般须要返回200,表示请求成功,其余状况则按照须要返回40三、40四、405等。

这里列出几个经常使用的响应码:

  • 200 OK
  • 201 CREATED
  • 204 NO CONTENT
  • 400 BAD REQUEST
  • 401 UNAUTHORIZED
  • 403 FORBIDDEN
  • 404 NOT FOUND
  • 405 METHOD NOT ALLOWED
  • 409 CONFLICT
  • 500 INTERNAL SERVER ERROR

还有什么?

是的,关于REST还有很是多的内容,但本文到这里就要告一段落了,而想要深刻了解REST的特性,乃至构建本身的RESTful Web系统,到此为止是远远不够的。

目前的主流编程语言,如Java、PHP、Python、Ruby、Node.js、C#等,都已经实现了各自的支持REST的编程框架,能够根据兴趣选择其中之一来学习并实践。

这里还有重要的阅读资料,以便深刻研究REST架构范式:

相关文章
相关标签/搜索