本文是「架構風格:你真的懂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的完整流程: