rest(RESTful)

rest(一種軟體架構風格)

RESTful一般指本詞條

本詞條是多義詞,共6個義項
更多義項 ▼ 收起列表 ▲

REST即表述性狀態傳遞(英文:Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟體架構風格。它是一種針對網路套用的設計和開發方式,可以降低開發的複雜性,提高系統的可伸縮性

在三種主流的Web服務實現方案中,因為REST模式的Web服務與複雜的SOAPXML-RPC對比來講明顯的更加簡潔,越來越多的web服務開始採用REST風格設計和實現。例如,Amazon.com提供接近REST風格的Web服務進行圖書查找;雅虎提供的Web服務也是REST風格的。

基本介紹

  • 中文名:表述性狀態轉移
  • 外文名:Representational State Transfer
  • 外語縮寫:REST
  • 提出時間:2000年
基本含義,使用原則,定義規則,所有連結一起,使用標準方法,資源多重表述,無狀態通信,MVC,套用場景,RESTful特點,優勢,缺點,

基本含義

REST 這個概念於 2000 年由 Roy Fielding( HTTP規範的主要編寫者之一)在就讀加州大學歐文分校期間在學術論文“Architectural Styles and the Design of Network-based Software Architectures”首次提出。論文中對使用 Web 服務作為分散式計算平台的一系列軟體體系結構原則進行了分析,其中提出的 REST 概念並沒有獲得太多關注。
REST是在Browser/Server的基礎上添加了另外3個規範性的組成,第一個為統一接口,第二個為分層系統,第三個為按需代碼。
統一接口為REST定義了對系統資源進行操作統一的方法和連結入口,REST架構的核心就是資源,它將網際網路中所有的可訪問、操作的數據信息都看作資源進行處理,從而簡化了REST對不同數據信息的處理方式和過程,也為REST的高度 重用性以及不同分散式異構系統的高互動性奠定了基礎。
分層系統的定義使得web Service的定義和實現Web系 統不同的層次之間具有良好的獨立性,從而降低了系統層次依賴耦合性和複雜性,而良好的接口封裝、套用功能實現等干擾性大大降低,從而為Web系統的可維護性、擴展性等奠定了良好的基礎。
按需代碼則是web Service可選的要求,通過按需代碼開發者可以在客戶端的應用程式進行功能擴展,從而實現對客戶需求的滿足,從而使得系統更加人性化,提升其友好性。

使用原則

大部分對REST的介紹是以其正式的定義和背景作為開場的。這裡提出一個簡要的定義:REST定義了Web的使用標準(這和大多數人的實際使用方式有很大不同),例如HTTP和URI。如果在設計應用程式時能堅持REST原則,那就預示著將會得到一個使用了優質Web架構(用戶受益)的系統。
REST 並非始終是正確的選擇。 它作為一種設計 Web 服務的方法而變得流行,這種方法對專有中間件(例如某個應用程式伺服器)的依賴比基於 SOAP 和 WSDL 的方法更少。 在某種意義上,通過強調URI和HTTP等早期 Internet 標準,REST 是對大型應用程式伺服器時代之前的 Web 方式的回歸。 正如已經在所謂的基於 REST 的接口設計原則中研究過的一樣,XML over HTTP 是一個功能強大的接口,允許內部應用程式(例如基於 Asynchronous JavaScript + XML (Ajax) 的自定義用戶界面)輕鬆連線、定位和使用資源。 事實上,Ajax 與 REST 之間的完美配合已增加了當今人們對 REST 的注意力。
通過基於 REST 的 API 公開系統資源是一種靈活的方法,可以為不同種類的應用程式提供以標準方式格式化的數據。 它可以幫助滿足集成需求(這對於構建可在其中容易地組合 (Mashup) 數據的系統非常關鍵),並幫助將基於 REST 的基本服務集擴展或構建為更大的集合。

定義規則

REST中的資源所指的不是數據,而是數據和表現形式的組合,比如“最新訪問的10位會員”和“最活躍的10位會員”在數據上可能有重疊或者完全相同,而由於他們的表現形式不同,所以被歸為不同的資源,這也就是為什麼REST的全名是Representational State Transfer的原因。資源標識符就是URI(Uniform Resource Identifier),不管是圖片,Word還是視頻檔案,甚至只是一種虛擬的服務,也不管是XML標準通用標記語言下的一個子集)格式、txt檔案格式還是其它檔案格式,全部通過 URI對資源進行唯一的標識。
對資源使用一致的命名規則(naming scheme)最主要的好處就是不需要提出自己的規則——而是依靠某個已被定義,在全球範圍中幾乎完美運行,並且能被絕大多數人所理解的規則。想一下構建的上一個套用(假設它不是採用RESTful方式構建的)中的任意一個高級對象(high-level object),那就很有可能看到許多從使用唯一標識中受益的用例。比如,如果套用中包含一個對顧客的抽象,那么可以相當肯定,用戶會希望將一個指向某個顧客的連結,能通過電子郵件傳送到同事那裡,或者加入到瀏覽器的書籤中,甚至寫到紙上。更透徹地講:如果在一個類似於Amazon的線上商城中,沒有用唯一的ID(一個URI)標識它的每一件商品,可想而知這將是多么可怕的業務決策
當面對這個原則時,許多人驚訝於這是否意味著需要直接向外界暴露資料庫記錄(或者資料庫記錄ID)——自從多年以來面向對象的實踐經驗,要將持久化的信息作為實現細節隱藏起來之後,哪怕是剛有點想法都常會使人驚恐。但是這條原則與隱藏實現細節兩者之間並沒有任何衝突:通常,值得被URI標識的事物——資源——要比資料庫記錄抽象的多。例如,一個訂單資源可以由訂單項、地址以及許多其它方面(可能不希望作為單獨標識的資源暴露出來)組成。標識所有值得標識的事物,領會這個觀念可以進一步引導用戶創造出在傳統的應用程式設計不常見的資源:一個流程或者流程步驟、一次銷售、一次談判、一份報價請求——這都是應該被標識的事物的示例。同樣,這也會導致創建比非RESTful設計更多的持久化實體。
下面是一些用戶可能想到的URI的例子:
註:網址中的“*”代表“.”
http://example*com/customers/1234
http://example*com/orders/2007/10/776654
http://example*com/products/4554
http://example*com/processes/salary-increase-234
正如選擇了創建便於閱讀的URI——這是個有用的觀點,儘管不是RESTful設計所必須的——應該能十分容易地推測出URI的含義:它們明顯地標識著單一“數據項”。但是再往下看:
http://example*com/orders/2007/11
http://example*com/products?color=green
首先,這兩個URI看起來與之前的稍有不同——畢竟,它們不是對一件事物的標識,而是對一類事物集合的標識(假定第一個URI標識了所有在2007年11月份提交的定單,第二個則是綠顏色產品的集合)。但是這些集合自身也是事物(資源),也應該被標識。
注意,使用唯一、全局統一的命名規則的好處,既適用於瀏覽器中的Web套用,也適用於機對機(machine-to-machine,m2m)通信。

所有連結一起

接下來要討論的原則有一個有點令人害怕的正式描述:“超媒體作為套用狀態的引擎(Hypermedia as the engine of application state)”,有時簡寫為HATEOAS。嚴格地說這個描述的核心是超媒體概念,換句話說:是連結的思想。連結是在HTML標準通用標記語言下的一個套用)中常見的概念,但是它的用處絕不局限於此(用於人們網路瀏覽)。
應用程式(已經檢索過文檔)如何“跟隨”連結檢索更多的信息。當然,如果使用一個遵守專用命名規範的簡單“id”屬性作為連結,也是可行的——但是僅限於套用環境之內。使用URI表示連結的優雅之處在於,連結可以指向由不同套用、不同伺服器甚至位於另一個大陸上的不同公司提供的資源——因為URI命名規範是全球標準,構成Web的所有資源都可以互聯互通
超媒體原則還有一個更重要的方面——套用“狀態”。簡而言之,實際上伺服器端(也可以叫服務提供者)為客戶端(服務消費者)提供一組連結,使客戶端能通過連結將套用從一個狀態改變為另一個狀態。
對此原則總結如下:任何可能的情況下,使用連結指引可以被標識的事物(資源)。

使用標準方法

在前兩個原則的討論中暗含著一個假設:接收URI應用程式可以通過URI明確地做一些有意義的事情。如果在公共汽車上看到一個URI,可以將它輸入瀏覽器的地址欄中並回車——但是瀏覽器如何知道需要對這個URI做些什麼。
它知道如何去處理URI的原因在於所有的資源都支持同樣的接口,一套同樣的方法(也可以稱為操作)集合。在HTTP中這被叫做動詞(verb),除了兩個大家熟知的(GET和POST)之外,標準方法集合中還包含PUT、DELETE、HEAD和OPTIONS。這些方法的含義連同行為許諾都一起定義在HTTP規範之中。一名OO開發人員,就可以想像到RESTful HTTP方案中的所有資源都繼承自類似於這樣的一個類(採用類Java、C#的偽語法描述,請注意關鍵的方法):
class Resource {
    Resource(URI u);
    Response get();
    Response post(Request r);
    Response put(Request r);
    Response delete();
}
由於所有資源使用了同樣的接口,可以依此使用GET方法檢索一個表述(representation)——也就是對資源的描述。因為規範中定義了GET的語義,所以可以肯定當調用它的時候不需要對後果負責——這就是為什麼可以“安全”地調用此方法。GET方法支持非常高效、成熟的快取,所以在很多情況下,甚至不需要向伺服器傳送請求。還可以肯定的是,GET方法具有冪等性[譯註:指多個相同請求返回相同的結果]——如果用戶傳送了一個GET請求沒有得到結果,可能不知道原因是請求未能到達目的地,還是回響在反饋的途中丟失了。冪等性保證了可以簡單地再傳送一次請求解決問題。冪等性同樣適用於PUT和DELETE方法。POST方法,通常表示“創建一個新資源”,也能被用於調用任意過程,因而它既不安全也不具有冪等性。
如果採用RESTful的方式暴露套用功能(也可以稱為服務功能),那這條原則和它的約束同樣也適用。如果習慣於另外的設計方式,則很難去接受這條原則。
來看下面這個簡單的採購方案例子:
可以看到,例子中定義了兩個服務程式。這些服務程式的接口都是為了完成任務而定製的。如果客戶端程式試圖使用這些服務,那它必須針對這些特定接口進行編碼——不可能在這些接口定義之前,使用客戶程式去有目的地和接口協作。這些接口定義了服務程式的套用協定(application protocol)。
在RESTful HTTP方式中,將通過組成HTTP套用協定的通用接口訪問服務程式。可能會想出像這樣的方式:
rest(RESTful)
REST
可以看到,服務程式中的特定操作被映射成為標準的HTTP方法——為了消除歧義,創建了一組全新的資源。標識一個顧客的URI上的GET方法正好相當於getCustomerDetails操作。有人用三角形形象化地說明了這一點:
rest(RESTful)
REST
把三個頂點想像為可以調節的按鈕。可以看到在第一種方法中,擁有許多操作,許多種類的數據以及固定數量的“實例”。在第二種方法中,擁有固定數量的操作,許多種類的數據和許多調用固定方法的對象。它的意義在於,證明了通過這兩種方式,基本上可以表示任何用戶喜歡的事情。
使用標準方法如此重要,從根本上說,它使套用成為Web的一部分——應用程式為Web變成Internet上最成功的套用所做的貢獻,與它添加到Web中的資源數量成比例。採用RESTful方式,一個套用可能會向Web中添加數以百萬計的客戶URI;如果採用CORBA技術並維持套用的原有設計方式,那它的貢獻大抵只是一個“端點(endpoint)”——就好比一個非常小的門,僅僅允許有鑰匙的人進入其中的資源域。
統一接口也使得所有理解HTTP套用協定的組件能與套用互動。通用客戶程式(generic client)就是從中受益的組件的例子,例如curlwget、代理、快取、HTTP伺服器、網關還有Google、Yahoo!、MSN等等。
總結如下:為使客戶端程式能與資源相互協作,資源應該正確地實現默認的套用協定(HTTP),也就是使用標準的GET、PUT、POST和DELETE方法。

資源多重表述

客戶程式如何知道該怎樣處理檢索到的數據,比如作為GET或者POST請求的結果。原因是,HTTP採取的方式是允許數據處理和操作調用之間關係分離的。換句話說,如果客戶程式知道如何處理一種特定的數據格式,那就可以與所有提供這種表述格式的資源互動。再用一個例子來闡明這個觀點。利用HTTP內容協商(content negotiation),客戶程式可以請求一種特定格式的表述:
GET /customers/1234 HTTP/1.1
Host: example*com
Accept: application/vnd.mycompany.customer+xml
請求的結果可能是一些由公司專有的XML標準通用標記語言下的一個子集)格式表述的客戶信息。假設客戶程式傳送另外一個不同的請求,就如下面這樣:
GET /customers/1234 HTTP/1.1
Host: example*com
Accept: text/x-vcard     
結果則可能是VCard格式的客戶地址。這說明為什麼理想的情況下,資源表述應該採用標準格式——如果客戶程式對HTTP套用協定和一組數據格式都有所“了解”,那么它就可以用一種有意義的方式與世界上任意一個RESTful HTTP套用互動。當然以上情況不僅適用於從伺服器端到客戶端的數據,反之既然——倘若從客戶端傳來的數據符合套用協定,那么伺服器端就可以使用特定的格式處理數據,而不去關心客戶端的類型。
在實踐中,資源多重表述還有著其它重要的好處:如果為資源提供標準通用標記語言下的子集HTMLXML兩種表述方式,那這些資源不僅可以被套用所用,還可以被任意標準Web瀏覽器所用——也就是說,套用信息可以被所有會使用Web的人獲取到。
資源多重表述還有另外一種使用方式:可以將套用的Web UI納入到Web API中——畢竟,API的設計通常是由UI可以提供的功能驅動的,而UI也是通過API執行動作的。將這兩個任務合二為一帶來了令人驚訝的好處,這使得使用者和調用程式都能得到更好的Web接口。總結:針對不同的需求提供資源多重表述。

無狀態通信

無狀態通信是最後一個原則。首先,需要著重強調的是,雖然REST包含無狀態性(statelessness)的觀念,但這並不是說暴露功能的套用不能有狀態——事實上,在大部分情況下這會導致整個做法沒有任何用處。REST要求狀態要么被放入資源狀態中,要么保存在客戶端上。或者換句話說,伺服器端不能保持除了單次請求之外的,任何與其通信的客戶端的通信狀態。這樣做的最直接的理由就是可伸縮性—— 如果伺服器需要保持客戶端狀態,那么大量的客戶端互動會嚴重影響伺服器的記憶體可用空間(footprint)。(注意,要做到無狀態通信往往需要需要一些重新設計——不能簡單地將一些session狀態綁縛在URI上,然後就宣稱這個套用是RESTful。)
但除此以外,其它方面可能顯得更為重要:無狀態約束使伺服器的變化對客戶端是不可見的,因為在兩次連續的請求中,客戶端並不依賴於同一台伺服器。一個客戶端從某台伺服器上收到一份包含連結的文檔,當它要做一些處理時,這台伺服器宕掉了,可能是硬碟壞掉而被拿去修理,可能是軟體需要升級重啟——如果這個客戶端訪問了從這台伺服器接收的連結,它不會察覺到後台的伺服器已經改變了。

MVC

第一個問題假設REST是用戶應該採用的架構,然後討論如何使用;第二個問題則要說明REST和當前最普遍套用的MVC是什麼關係,互補還是取代?
REST除了給帶來了一個嶄新的架構以外,還有一個重要的貢獻是在開發系統過程中的一種新的思維方式:通過url來設計系統的結構。根據REST,每個url都代表一個resource,而整個系統就是由這些resource組成的。因此,如果url是設計良好的,那么系統的結構就也應該是設計良好的。對於非高手級的開發人員來說,考慮一個系統如何架構總是一個很抽象的問題。敏捷開發所提倡的Test Driven Development,其好處之一就是可以通過testcase直觀地設計系統的接口。比如在還沒有創建一個class的時候就編寫一個testcase,雖然設定不能通過編譯,但是testcase中的方法調用可以很好地從class使用者的角度反映出需要的接口,從而為class的設計提供了直觀的表現。這與在REST架構中通過url設計系統結構非常類似。雖然一個功能都沒有實現,但是可以先設計出認為合理的url,這些url甚至不能連線到任何page或action,但是它們直觀地表明:系統對用戶的訪問接口就應該是這樣。根據這些url,可以很方便地設計系統的結構。
重申一遍:REST允許通過url設計系統,就像Test Driven Development允許使用testcase設計class接口一樣。
網路套用通常都是有hierarchy的,像棵大樹。用戶通常希望url也能反映出資源的層次性。比如對於一個blog套用:/articles表示所有的文章,/articles/1表示id為1的文章,這都比較直觀。因此人們常常會問這樣一個問題:RESTful的url能覆蓋所有的用戶請求嗎?比如,login如何RESTful?search如何RESTful?
從REST的概念上來看,所有可以被抽象為資源的東東都可以使用RESTful的url。因此對於上面的兩個問題,如果login和search可以被抽象為資源,那么就可以使用RESTful的url。search比較簡單,因為它會返回搜尋結果,因此可以被抽象為資源,並且只實現index方法就可以了(只需要顯示搜尋結果,沒有create、destroy之類的東西)。然而這裡面也有一個問題:search的關鍵字如何傳給server?index方法顯然應該使用HTTP GET,這會把關鍵字加到url後面,當然不符合REST的風格。要解決這個問題,可以把每次search看作一個資源,因此要創建create和index方法,create用來在用戶點擊“搜尋”按鈕是通過HTTP POST把關鍵字傳給server,然後index則用來顯示搜尋結果。這樣一來,還可以記錄用戶的搜尋歷史。使用同樣的方法,也可以對login套用REST,即每次login動作是一個資源。
一開始可能想到的是/category/ruby/articles,這種想法很直觀。還有一種url形式,它對應到程式中的繼承關係。比如product是一個父類,book和computer是其子類。那么所有產品的url應該是/products,所有書籍的url應該是/books,所有電腦的url應該是/computers。這一想法就比較直觀了,而且再次驗證了url可以幫助進行設計的論點。
再說明一下如果每個用戶需求都可以抽象為資源,那么就可以完全使用REST。
由此看來,使用REST的關鍵是如何抽象資源,抽象得越精確,對REST的套用就越好。
有了對第一個問題的討論,第二個問題就容易討論多了。REST會取代MVC嗎?還是彼此是互補關係(就像AOP對於OOP)?答案是It depends!如果可以把所有的用戶需求都可以抽象為資源,那么MVC就可以退出歷史的舞台了。如果情況相反,那么就需要混合使用REST和MVC。
當然,這是非常理想的論斷。可能無法找到一種方法可以把所有的用戶需求都抽象為資源,因為保證這種抽象的完整性(即真的是所有需求都可以)需要形式化的證明。而且即使被證明出來了,由於開發人員的能力和喜好不同,MVC肯定也會成為不少人的首選。但是對於希望擁抱REST的人來說,這些都沒有關係。只要開發的系統所設計的問題域可以被合理地抽象為資源,那么REST就會成為開發利器。

套用場景

RESTful適用於許多不同的套用場景,包括:
1. Web 應用程式:RESTful可以用於構建Web應用程式,如社交媒體網站、部落格、線上商店等。
2. 移動應用程式:RESTful可以用於構建移動應用程式,如手機應用程式、平板電腦應用程式等。
3. 後端應用程式:RESTful可以用於構建後端應用程式,如資料庫伺服器、訊息佇列伺服器等。
4. 物聯網設備:RESTful可以用於構建物聯網設備,如智慧型家居設備、智慧型城市設備等。

RESTful特點

優勢

1. 可擴展性:RESTful使用無狀態協定,可以輕鬆地支持並發請求和負載均衡,從而提高系統的可擴展性。
2. 可靠性:RESTful使用HTTP 協定來傳輸數據,HTTP協定是一種通用的協定,可以保證數據的可靠性和安全性。
3. 易於使用和管理:RESTful使用標準化的概念和規則,如HTTP協定、URL、JSON等,使得開發人員可以更加輕鬆地設計和實現系統。
4. 跨平台支持:RESTful可以用於構建跨平台的應用程式,如Web應用程式、移動應用程式、後端應用程式等。

缺點

1.真實系統中的資源非常複雜,很難清晰地進行資源的劃分。
2.真實系統中的業務很複雜,並不是所有的操作都能簡單地對應到PUT、GET、DELETE、POST上。
3.真實系統是在不斷進化的,一個操作最開始的時候被設計為冪等的 PUT,但是後來的版本又修改了邏輯,可能該操作就變成了不冪等的。如果調用者繼續對這個操作進行重試可能會有副作用。
4.在 Restful 中,資源儘量通過 URL來定位,要儘量避免使用 QueryString 及請求報文體傳遞數據。
5.HTTP狀態碼的個數是有限的,特別是用於表示業務相關的錯誤碼主要在 4xx狀態碼段中,而業務系統中的錯誤非常複雜,僅通過 HTTP狀態碼來反映錯誤有時候會無法滿足要求。
6.有的客戶端是不支持 PUT、DELETE 請求的。例如: 舊版本的程式。
check!

熱門詞條

聯絡我們