本文是「架构风格:你真的懂REST吗?」的补充!html
REST全称是Representational State Transfer,目前广泛接受的中文翻译为「表述性状态转移」!java
即便翻译过来了,你依然有一堆疑问:web
因此本文试图回答以下几个问题:数据库
为何Fielding博士要取这么个难以理解的名字呢?其实REST论文的第六章给出了明确的答案:服务器
REST was originally referred to as the "HTTP object model," but that name would often lead to misinterpretation of it as the implementation model of an HTTP server. The name "Representational State Transfer" is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through the application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use.
REST原本是想叫「HTTP object model」的,可是这个名字会给人误解,让人误觉得REST是一个HTTP服务器的实现。叫REST这个名字的目的是为了暗示一个「设计良好的Web应用」应该有怎样的行为:一个由web页面组成的网(一个虚拟状态机),用户经过选择连接在应用中前进(状态变迁),用户的选择会致使下一个页面(表明应用的下一个状态)被转移到用户端、并被渲染出来以供使用!架构
Tips:注意上面括号里的单词(state transitions),这里是transitions而不是transfer。transitions表示的是过渡、切换、变迁,好比场景的切换,就是从一个场景到了另外一个场景。这里是从一个状态切换到了另外一个状态。REST中文文档里,仍是将其翻译成了「转移」,应该是不正确的!app
网上不少讨论REST的文章或帖子,关注的点有两个:ide
而从上面这段话,你会发现,重点既不是Representational、也不是Transfer,而是State!你有没有以为上面所提到的State和你平时所理解的State有差别?或者说比较违和?翻译
咱们都知道,要保证服务端的伸缩性,就要确保服务端是无状态的!若是是「无状态」的,那么为何有「状态的变迁」呢?难道REST没有伸缩性?显然不是,要知道,Web但是现今伸缩性最好的系统!设计
因此这里所指的State与咱们平时所说的State不是一个概念!这里的State是「应用状态」,咱们所说的State是「资源状态」(这里所说的资源和REST中所指的资源也是不同的,下面会说到)!
先说应用状态,在上文中,能够看到。应用状态指的是一个个的Web页面!Web页面上有连接,你点击连接后,这个连接所对应的「应用状态」会从服务器「转移」到客户端,渲染出来,展现给你。你就「切换」到了下一个「应用状态」!
因此「State Transfer」指的是:「应用状态」从服务端「转移」到了客户端,致使客户端的「应用状态」从当前状态「变迁」到了下一个状态!
在解释「资源状态」以前,要先来解释一下什么是「资源」?什么是「表述」?
早期URI设计时,「资源」表示的是「文档」!它假设万维网里转移的都是文档!如今看来,显然不是!REST对「资源」进行了抽象!
通常咱们对资源的理解是「能够在万维网里转移的任何内容」,好比:网页、图片、视频等!但实际上,REST论文中给出的定义和咱们日常所理解的「资源」差别仍是很大的!
REST论文中给出的解释:
The resource is not the storage object. The resource is not a mechanism that the server uses to handle the storage object. The resource is a conceptual mapping -- the server receives the identifier (which identifies the mapping) and applies it to its current mapping implementation (usually a combination of collection-specific deep tree traversal and/or hash tables) to find the currently responsible handler implementation and the handler implementation then selects the appropriate action+response based on the request content.
资源不是存储对象!也不是服务器处理存储对象的机制!资源是一个概念上的映射关系:服务器接收到标示符(这些标示符标示了这个映射关系),将其应用到当前的映射实现上(通常是特定集合【深度遍历的树和/或哈希表】的组合)来找到当前负责处理该请求的处理器、这个处理根据请求内容选择合适的动做+响应
我用一段伪代码来解释一下!
var mappingImpl = {'/pathA':handlerA,'/pathB':handlerB,'/pathC':handleC,...} mappingImpl.get('/pathB').handle(req);
按照这个定义的话,实际上REST中所指的「资源」和咱们日常所指的「资源」根本不是同一个东西:
你会发现,REST中的资源是个「动态」的东西,而咱们所说的资源是个「静态」的东西,或者说就是个类型多样化的「文档」而已!
用伪代码表示的话就是:
var resourceMap = {'/pathA':resourceA,'/pathB':resourceB,'/pathC':resourceC,...} resourceMap.get('/pathB');
实际上,现代Web应用中,绝大部分URI标示的都是动态的内容!因此在这一点上,REST对资源的定义更加的准确!
你可能会说,这二者的区别可能不是那么大,由于不管资源指的是关系仍是处理结果,咱们最终都是看到的是同样的内容!你肯定吗?
假设资源就是咱们日常所理解的「返回结果」:
resourceMap.getOrDefault('/pathD','这里该返回什么?');
返回「空资源」?那什么是「空资源」,如何表示「空资源」?null吗?那客户端又如何处理这个特殊的null呢?或者说是一个「Null资源」?「Null资源」是资源吗?既然是没有资源,那还叫资源吗?是否是很拗口?
REST经过表述来解决这个问题:
mappingImpl.getOrDefault('/pathD',defaultHandler).handle(req); // 若是找不到对应的处理器就用默认处理器处理。 //若是找不到请求内容对应的响应,就返回一个没有内容的表述
上面所说的Web页面就是一种表述,也就是说表述是「应用状态」!
因此对REST的理解应该是:经过连接,以表述的方式,将应用状态从服务端转移到客户端!
解释完资源和表述,最后来解释一下「资源状态」!
不少关于RESTful的博文,主要讲的是:
以User为例:
GET /users // 获取用户列表 GET /user/1 // 获取ID为1的用户信息 POST /user // 建立用户 PUT /user/1 // 更新ID为1的用户信息 DELETE /user/1 // 删除ID为1的用户信息
这里的POST,PUT,DELETE改变的是「资源状态」!和上面所说的「应用状态」是两回事!不少地方都没有明确的区分开来!
记得当初看JVM的时候,也有相似的状况!JVM中有三个栈,虚拟机栈、操做数栈和本地方法栈。不少地方都直接叫作栈,这就致使了理解的混乱!前面说一个方法的调用就是将对应的栈帧入栈;后面又说指令的执行,对应的操做数入栈。实际上前一个栈指的是虚拟机栈,后一个栈指的是操做数栈!
在这里状况相似,状态没有区分开,也会致使理解的混乱!前面说「状态的转移」,这里又说「状态的改变」!一个是「应用状态的转移」,一个是「资源状态的改变」!
若是按照上面对资源的理解的话,这里的状态其实不该该叫「资源状态」,而应该是「内容状态」!
下面以User的CRUD为例,来讲明一下REST的完整流程: