REST服務開發實戰
REST介紹
如果要說什么是REST的話,那最好先從Web(萬維網)說起。
什么是Web呢?讀者可以查看維基百科的詞條(http://zh.wikipedia.org/zh-cn/Web),具體的我就不多說了。總之,Web是我們在互聯網上最常用的服務,甚至在某些人的心中,互聯網就是Web。當然,Web只是互聯網的一部分而已,只是大家用的最多而已,我們訪問的所有網站都是基于Web。
那么,Web和REST之間究竟有什么關系呢?我們接下來將聊聊組成Web的幾大基礎技術,URI(統一資源標識符,用來標識資源)、HTTP(超文本傳輸/轉移協議,用來操作資源)、Hypertext(超文本,用來描述資源的內容與狀態,我們可以用HTML、XML、JSON或者自定義格式的文本來描述任何一個資源)。
那我們再來看看什么是REST呢?其實REST并不是一種新興的技術語言,也不是什么新的技術框架。準確來說說REST只是一種概念、風格或者約束,是回歸HTTP本身的建議。
REST是由Roy Thomas Fieding在他的博士論文《Architectural Styles and the Design of Network-based Software Architectures》(《架構風格與基于網絡的軟件架構設計》)中提出的一種架構思想。Roy Fielding是Apache基金會的合作創作者,同時也是HTTP、URI等Web基礎協議的主要設計者。從Roy Fielding的背景,我想大家就應該能了解到REST與Web之間的關系了吧。的確,在REST中我們關注技術實際上也只是URI、HTTP、Hypertext而已。
Roy在他的論文中提出了一個RESTful應用應該具備的幾點約束。
- 每個資源都應該有一個唯一的標識
- 使用標準的方法來更改資源的狀態
- Request和Response的自描述
- 資源多重表述
- 無狀態的服務
Roy認為,只有具備了上面的約束的應用才能算是REST應用,其實現在好多所謂的REST應用或服務,其實并不能算是真正的REST應用。
我發現,其實目前很多所謂的REST應用,只是RPC而已,出現這樣的情況其實很正常,因為RPC實際上更符合一般程序員的思維。其實REST和RPC之間還是有很大的差異的,下面我們說一說REST和RPC之間的區別。
- REST強調資源有唯一的URI;而RPC更加強調過程(動詞),由統一的接口來調用它們。
- REST回歸HTTP最初的設計;RPC僅僅只是把HTTP作為傳輸協議來使用。
- REST是由超文本驅動的;RPC是由方法驅動的。
- REST強調HTTP通信的語義可見性,通過消息頭和標準的HTTP方法來體現;RPC把語義封裝在HTTP消息體中。
REST的應用場景
通過上面的介紹,大家應該對REST有一些最基本的了解,由于RESTf應用的這些約束,我們可以很輕易的了解和使用REST的服務(只要你了解HTTP)。
其實,我們經常容易犯一個錯誤就是,當我們了解了一個新的技術,就會用這個技術來解決所有的問題。有一句諺語是這么來說的:“在錘子的眼里,所有的東西都是釘子”,其實REST也只是我們工具箱里面的其中的一個工具而已,希望不要把它當做我們唯一的工具。那么我們就來聊聊適合使用REST的應用場景和不適合使用REST的應用場景。
在我看來REST最適合的應用場景其實是需要對外暴露服務的時候,這個時候,我們可以充分利用REST的自描述、無狀態、唯一標識等特性來提供清晰、友好的API,而且現在的Jesery、RESTEasy等JAX-RS框架也提供了OAuth的支持,基本上能夠保證服務安全。
最不適合的應用場景是對性能要求高的系統內部之間的服務調用,當你在這個時候使用REST的話,那么REST所有的特性都會變成拖累。這個時候,還是需要選擇更底層的通信協議和方式會更好一些,比如ICE。這樣的錯誤,我曾經犯過,后來通過很長時間的努力才慢慢的將這個錯誤改過來。
規劃REST服務
當我們要規劃一個REST服務的時候,其中最關鍵的概念其實就是“資源”。
資源是什么呢?廣義上講,任何事物只要它有用,那么它就是資源。狹義的講(在Web環境中),它是一個可以存放、連接在計算機上,可以通過比特流進行操控的實體。一個實體想成為資源,它必須有一個URI。在這里URI包含了兩重含義:1)它是資源的名稱 2)它是資源的地址。
在我們規劃URI的時候,有幾點希望大家能夠注意一下:
- 一個URI標識一個資源,但是一個資源可以被多個URI標識。
- 資源也是有層次的,這個層次應該在URI上充分的體現出來。
- 在規劃URI的時候,需要定義一些團隊內部確認的關鍵字或符號,這些關鍵字或符號是有特殊意義的,不能隨便使用。
- 需要有一個URI定義的文檔,以備以后的查詢和維護。
- 可以使用URI Template來描述URI的定義。如何使用URI Template也看看這篇文章
當我們定義好資源之后,接下來要做的事情就是定義操作資源的方法以及資源的表述格式了。
使用HTTP提供的基本方法來對資源進行操作,一般的操作定義如下:POST(創建資源)、GET(獲取資源)、PUT(修改資源)、DELETE(刪除)。它們正好對應了CRUD。
對資源的表述,一般的選擇會是XML,但是我更加推薦使用JSON來表述資源。在網絡中的傳輸量也小,而且也便于JavaScript來解析,而且現在其他語言解析也是非常方便的事情。不過,最關鍵的還是占用更少的資源,讓同樣的資源能夠服務更多的人。
下面的這張圖就很好的說明了REST中最重要的圍繞資源的三角關系。
在InfoQ上有一篇很好的文章來介紹如何規劃REST服務《如何獲取(GET)一杯咖啡——星巴克REST案例分析》,估計大家看完這篇文章,應該對如何規劃REST服務會有更深的認識。
選擇一個快速方便的REST框架
現在REST的框架也非常多,推薦大家使用Jersey和RESTEasy來創建自己的REST服務。
這兩個框架都出自名門,Jersey是由SUN提供的JAX-RS實現參考,對JAX-RS支持的最為充分和快速,基本上所有的JAX-RS的新特性都會在Jersey里第一個體現出來,而且提供了相當全了例子讓你學習。RESTEasy則是有JBoss開源的項目,它同樣有很多優點,而且文檔也比Jersey更好一些,但是和他JBoss應用服務器綁定的比較緊密,這點我個人不太喜歡,如果是熟悉JBoss應用服務器的人可以選擇RESTEasy,它給人的感覺更加成熟一些,不像Jersey會很快的加入新的特性。不過,需要根據個人自己的喜好來選擇。
如何使用Jersey來快速創建REST應用,參見通過Jersey快速構建REST應用,如何使用RESTEasy快速創建REST應用,參見使用RESTEasy快速創建REST應用。
發布REST服務需要注意的地方
之前我也提到了使用REST的最佳的場景是對外提供公開的服務,也就是所謂的OpenAPI。一旦開放了API,我們就很難控制這些API的使用及其調整了,如果在開放這些API之前考慮的不周到的話,那么后期的維護那就會是一個非常麻煩的事情了。所以,當我們決定要開放API的時候,那么我們一定要注意一些事情,下面的這些算是我的經驗總結。
對外暴露API時,需要注意版本規劃,以便以后API的升級和維護。API的版本規劃,在開始開放API的之前,是一件很容易被忽視的。但是一旦你的API開放之后,那么你就會發現,沒有對開放的API進行版本規劃,是一件非常愚蠢的事情。當你的API使用的人越來越多,當你的開放的API越來越多,一旦某個API要升級,輸入和輸出發生變化的時候,你根本不知道該通知誰來升級,解決問題的時候也非常麻煩。
同樣,由于對外暴露API之后,你很難控制API被調用的次數和意圖,需要在一些關鍵的API被調用的次數和頻率上進行控制,以免受到惡意的攻擊。但是,到底次數和頻率應該控制在一個什么樣的程度,就要看你的API的關鍵程度以及負載能力了,每個系統都會有自己的評判,只要你掌握好了這個尺度,應該都不會有問題的。
另外,由于現在瀏覽器的限制,只能使用HTTP的GET和POST方法,如果通過AJAX直接調用REST服務,當你的服務中需要使用HTTP的PUT或者DELETE方法來調用的話,最好是考慮使用重載POST方式將需要使用PUT和DELETE方法調用的服務能夠通過POST來調用。
關于作者
鄧濤(Tony Deng),目前從事移動互聯網領域,關注高性能、高并發的互聯網架構。