文章目錄
- 引言
- REST 的誕生
-
- Web 技術發展
- REST 的誕生
- REST 詳解
-
- REST 架構風格
- 解讀 REST
-
- 1. 資源(Resources)
- 2. 表現層(Representation)
- 3. 狀态轉化(State Transfer)
- 4. 綜述
- REST 與 RESTful
- REST 風格優點
- REST實踐體會
-
- 1. URI命名難度變大
- 2. 用不用HTTP PATCH
引言
在網際網路高度普及的今天,作為一名Web開發者,如果你還沒聽說過“REST”這個技術名詞,出門都不好意思跟人打招呼。盡管如此,對于REST這個泊來品的了解,大多數人仍然停留在“盲人摸象”的階段。
有人認為,在Web Controller層寫的API就是REST API。而且,從開發角度對于URI的命名、HTTP Mehthod的選擇沒有建立起規範的意識。這樣是不優雅的!(沒有對錯之分)
作為帶着問題學習總結的我,未打算通過本篇文檔全面的闡述清楚REST,而是盡量的總結一些理論和思考,一起探讨!
REST 的誕生
Web 技術發展
Web開發技術的發展可以粗略劃分成以下幾個階段:
- 靜态内容階段:在這個最初的階段,使用Web的主要是一些研究機構。Web由大量的靜态HTML文檔組成,其中大多是一些學術論文。Web伺服器可以被看作是支援超文本的共享檔案伺服器。
- 可以想象下當時的HTTP請求隻有“GET”,且MIME為“HTML或TEXT”
- CGI程式階段:在這個階段,Web伺服器增加了一些程式設計API。通過這些API編寫的應用程式,可以向用戶端提供一些動态變化的内容。Web伺服器與應用程式之間的通信,通過CGI(Common Gateway Interface)協定完成,應用程式被稱作CGI程式。
- 腳本語言階段:在這個階段,伺服器端出現了ASP、PHP、JSP、ColdFusion等支援session的腳本語言技術,浏覽器端出現了Java Applet、JavaScript等技術。使用這些技術,可以提供更加豐富的動态内容。
- 瘦用戶端應用階段:在這個階段,在伺服器端出現了獨立于Web伺服器的應用伺服器。同時出現了Web MVC開發模式,各種Web MVC開發架構逐漸流行,并且占據了統治地位。基于這些架構開發的Web應用,通常都是瘦用戶端應用,因為它們是在伺服器端生成全部的動态内容。
- RIA應用階段:在這個階段,出現了多種RIA(Rich Internet Application)技術,大幅改善了Web應用的使用者體驗。應用最為廣泛的RIA技術是DHTML+Ajax。Ajax技術支援在不重新整理頁面的情況下動态更新頁面中的局部内容。同時誕生了大量的Web前端DHTML開發庫,例如Prototype、Dojo、ExtJS、jQuery/jQuery UI等等,很多開發庫都支援單頁面應用(Single Page Application)的開發。其他的RIA技術還有Adobe公司的Flex、微軟公司的Silverlight、Sun公司的JavaFX(現在為Oracle公司所有)等等。
- 移動Web應用階段:在這個階段,出現了大量面向移動裝置的Web應用開發技術。除了Android、iOS、Windows Phone等作業系統平台原生的開發技術之外,基于HTML5的開發技術也變得非常流行。
REST 的誕生
從上述Web開發技術的發展過程看,Web從最初其設計者所構思的主要支援靜态文檔的階段,逐漸變得越來越動态化。Web應用的互動模式,變得越來越複雜:從靜态文檔發展到以内容為主的門戶網站、電子商務網站、搜尋引擎、社交網站,再到以娛樂為主的大型多人線上遊戲、手機遊戲。
Web發展到了1995年,在CGI、ASP等技術出現之後,沿用了多年、主要面向靜态文檔的HTTP/1.0協定已經無法滿足Web應用的開發需求,是以需要設計新版本的HTTP協定。在HTTP/1.0協定專家組之中,有一位年輕人脫穎而出,顯示出了不凡的洞察力,後來他成為了HTTP/1.1協定專家組的負責人。這位年輕人就是Apache HTTP伺服器的核心開發者Roy Fielding,他還是Apache軟體基金會的合作創始人。
是以,REST 并不是在網際網路誕生之初就有的,它是在HTTP/1.1協定中才出現的,由Roy Thomas Fielding這位大神對Web技術做了深入的總結和分析,提出的一套網絡軟體的架構風格理論架構,當時Fielding為這種架構風格取了一個輕松愉快的名字:“REST” ———— Representational State Transfer(表述性狀态轉移)
- Roy Thomas Fielding 關于REST的論文
- https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf
REST 詳解
REST 架構風格
問題:REST 究竟是什麼?是一種新的技術、一種新的架構、還是一種新的規範?
首先,REST是Web自身的
架構風格
,也是世界上最成功的分布式應用架構風格。它是為運作在網際網路環境的分布式超媒體系統量身定制的。
- REST是一種架構風格!
- REST是一種架構風格!
- REST是一種架構風格!
是以,就會存在實際開發工作中即使沒有正确的了解和應用REST,但也能順利的完成開發工作。也正因為如此,給開發工作中推廣正确實踐和統一風格帶來不小的困難。因為大多數程式員總是在尋找最快解決問題,最快完成需求的方式,怎麼簡單怎麼來。
解讀 REST
REST ———— Representational State Transfer (表現層狀态轉化)
從“Representational State Transfer”這個定義去了解REST架構風格原則。
1. 資源(Resources)
REST 的名稱“表現層狀态轉化”中,省略了主語。“表現層”其實指的是“資源(Resources)”的“表現層”
資源是一種看待伺服器的方式,此處指的“資源”是一個抽象的概念,它不僅僅指伺服器端真實存在的檔案、資料庫表,而是指任何可被名詞表述的東西。是以在定義“資源”時可以要多抽象就多抽象。
對于用戶端,可以将伺服器端看作是由很多離散的資源組成。服務端可以用URI(統一資源定位符)指向資源,每種資源都對應一個特定的URI。要向擷取這個資源,通路它的URI就可以了,是以URI就成了每一個資源的位址或獨一無二的識别符。
所謂“上網”,就是與網際網路上一系列的“資源”互動,調用它的URI。
2. 表現層(Representation)
"資源"是一種資訊實體,它可以有多在的表現形式。我們把“資源”具體呈現出來的形式,叫做它的“表現層(Representation)”
比如,文本資訊可以用txt格式表現,也可以用HTML格式 、XML格式、JSON格式表現,甚至可以用二進制格式;圖檔可以用JPG格式表現,也可以用PNG格式表現。
URI隻代表資源的實體,不代表它的表現形式。資源的具體表現形式,應該在HTTP請求的的頭部資訊中用Accept和Content-Type字段指明,這兩個字段才是對“表現層”的描述。
- 詳見HTTP MIME明細
3. 狀态轉化(State Transfer)
HTTP協定是一個無狀态的協定,這意味着所有資源的狀态都儲存在伺服器端。因為用戶端想要操作伺服器,必須通過某種手段,讓伺服器端資源發生“狀态轉化”。而這種轉化是建立在表現層之上的,是以就是“表現層狀态轉化”。
用戶端用到的手段,隻能是HTTP協定。具體對應HTTP協定中的HTTP Method:GET、POST、PUT、PATCH、DELETE、HEAD、OPTIONS。每一種HTTP Method代表資源狀态轉化的一種
約定的
方式。
HTTP 動詞
對于資源的具體操作類型,有HTTP動詞表示。
常用的HTTP動詞如下:
- GET : 從伺服器取出資源(一個或多個)
- POST : 在伺服器建立一個資源,并傳回建立後的完整資源到用戶端
- PUT : 在伺服器以覆寫形式,全量更新資源,并傳回更新後的完整資源到用戶端
- PATCH : 在伺服器端更新資源,但隻更新指定的内容
- DELETE : 在伺服器端删除資源
其中,GET、PUT、PATCH、DELETE都應該是幂等的。
另外,HEAD、OPTIONS對于團隊開發來說基本不用。
- HEAD : 擷取資源的中繼資料
- OPTIONS : 擷取資訊,關于資源的哪些屬性是用戶端可以改變的
4. 綜述
綜合上面的解讀,總結一下什麼是REST架構風格:
(1) 伺服器端的任何資訊和資料都要被抽象資源化;
(2) 資源用URI進行表述,每一個URI代表一種資源;
(3) 用戶端與伺服器之間,基于某種表現層形式,互相傳遞資源;
(4) 用戶端與伺服器之間,基于HTTP Method對伺服器端資源的操作,實作“表現層狀态轉化”;
REST 與 RESTful
定義:
- 如果一個架構符合REST原則,就稱它為RESTful架構
- 如果HTTP API的設計符合REST原則,那麼可稱它為RESTful API
是以,回到開篇講的大多數人對于REST還是處于“盲人摸象”的階段,回想下自己和身邊的同僚,在工作中經常交流到的REST API或RESTful API,其實隻能算個HTTP API吧?
REST 風格優點
架構風格不是非此即彼的是非題,在實際開發中可以自主的選擇是否應用REST風格。那麼,如果應用REST風格會帶來哪些優勢呢?
- 從面向操作程式設計,轉變為面向資源程式設計。更面向對象,架構更清晰、松耦合。
- 我們應該确定的認為系統由“資源+對資源的操作”組成,而不是由“操作”組成
- 面向操作程式設計會導緻API膨脹,功能重複度高。
- 統一URI命名風格,URI具備很強的可讀性,具備自解釋的能力。伺服器資源層次目錄清晰。
- 狀态無關。確定系統橫向擴充的能力。
- 超文本驅動。確定系統演化的能力。
REST實踐體會
1. URI命名難度變大
在沒有要求URI必須用資源名詞來組成URI時,URI的命名從來不是什麼難事,常見的命名風格有:
- 動詞+名詞
- /deposit/getUsers: 擷取某個項目保證金使用者清單
- /orders/submitAudit: 訂單送出稽核
- /cart/add: 商品加購物車
- URI全局唯一即可
- /finance/budget/getPurchaseplanNextAuditOrgList:我有點小無語…
為什麼會這樣:
我們平時搞系統是這樣的:
- 有建立使用者功能
- 建立使用者需要一個URL
- 往這個URL發送的資料要定義好
- 開始寫後端和前端
這是以操作為第一位的設計方法,首先确認了一個操作,然後圍繞這個操作把周邊需要的東西建設好,這種方式當然可以架構出一個系統,甚至是一個好系統,但是偶爾會有些問題:
- 操作之間是會有關聯,你的設計容易變成“第2個操作要求第1個操作進行過”,這種關系多起來你的系統就亂了
- 你的URL設計會缺乏一緻性
- 操作通常被認為是有副作用(Side Effect)的,是以很少有人基于操作去設計緩存之類的東西
該怎麼應對?
确實,REST是高度抽象的理論和風格,在實際開發中會面對各種複雜的功能和場景,導緻很難完全的應用REST風格。當我們在争論REST風格到底如何設計才是正宗時,發現心中的困惑不僅沒有降低,反而增加了。
我的想法:仍以真正的系統需求為出發點,使用REST風格讓系統的架構更清晰,讓系統的開發協作更高效。部分不适合REST的場景應該靈活變通。
回到URI的命名:
- 堅持URI仍以資源為導向,清晰的表述伺服器端資源目錄
- 保障URI資源層次清晰的情況下,隻允許在URI最末一級添加動詞,例如:/market/orders/1/audit
- 如果某些動作是HTTP動詞表示不了的,考慮把動作抽象成一種資源
比如:網上彙款,從賬戶1向賬戶2彙款100元,錯誤的URI
POST /accounts/1/transfer/500/to/2
正确的寫法是把動詞transfer改成名詞transaction
POST /transaction?from=1&to=2&amount=100
2. 用不用HTTP PATCH
PATCH 作為HTTP的Method之一,其實它是2010年3月份才正式成為HTTP Method的,詳見:RFC 5789
也正因為PATCH出現的晚, 是以并不是所有Web容器都支援,反而目前實作了PATCH方法的Web容器很少
幾個常見Web容器實作PATCH方法的情況,供參考:
- Apache HttpComponents HttpClient version 4.2 or later 支援了 PATCH
- 目前 JDK7 的 HttpURLConnection 未實作 PATCH
- TOMCAT 7 也不行
- PlayFramework 2 也不支援
- Spring 3.2 開始支援 PATCH 方法,但要選對部署的容器
- JBoss Netty 支援 PATCH,可見: http://docs.jboss.org/netty/3.2/api/org/jboss/netty/handler/codec/http/class-use/HttpMethod.html