如今微服務(wù)和分布式架構(gòu)變的越來(lái)越流行蹬跃,而簡(jiǎn)單,可靠,高效维费,跨平臺(tái)和跨語(yǔ)言的 Web Service 則是這類(lèi)系統(tǒng)架構(gòu)的基石果元。 RESTful Web Service 恰好滿(mǎn)足這些特點(diǎn),被越來(lái)越多的系統(tǒng)架構(gòu)所采用犀盟。
本文主要面向?qū)?Web Service 有一定理解而晒,需要進(jìn)一步了解基于 REST 形式的 Web Service 的 IT 開(kāi)發(fā)人員和架構(gòu)師。它不是 Web Service 入門(mén)介紹阅畴,你需要較多相關(guān)領(lǐng)域的知識(shí)背景才能理解全部?jī)?nèi)容倡怎。
什么是 RESTful Web Service
作為互聯(lián)網(wǎng)應(yīng)用開(kāi)發(fā)人員,我們經(jīng)常能看到 Web Service贱枣,REST 和 RESTful Web Service 之類(lèi)的描述监署,可我們真的清楚這些概念嗎?
Web Service 簡(jiǎn)單來(lái)說(shuō)是指提供給不同設(shè)備通過(guò)互聯(lián)網(wǎng)(一般使用 HTTP 協(xié)議)進(jìn)行通信和交換數(shù)據(jù)的一種服務(wù)纽哥。RESTful Web Service 是實(shí)現(xiàn) Web Service 的一種方式钠乏。那么到底什么是 RESTful Web Service呢?什么又是 REST 呢春塌?
REST 和 RESTful Web Service
REST (Representational State Transfer) 是由美國(guó)計(jì)算機(jī)科學(xué)家 Roy Fielding在2000年的博士論文提出的一種架構(gòu)方式晓避。Roy Fielding絕對(duì)可以稱(chēng)之為業(yè)界大牛,他現(xiàn)任 Adobe 首席科學(xué)家只壳,是HTTP協(xié)議的首要作者之一俏拱,也是Apache項(xiàng)目的聯(lián)合創(chuàng)始人。
REST 是一種架構(gòu)方式和約定吼句,和具體實(shí)現(xiàn)無(wú)關(guān)锅必,也不一定必須基于Web。我們一般把采用 REST 架構(gòu)的 Web Service 稱(chēng)之 RESTful Web Service惕艳。在實(shí)際項(xiàng)目應(yīng)用中况毅,嚴(yán)格來(lái)說(shuō),我們應(yīng)該稱(chēng)這種 Web Service 為具有 REST 風(fēng)格的 Web Service尔艇。原因是我們?cè)谔幚砗徒鉀Q某些實(shí)際問(wèn)題時(shí)尔许,這種 Service 可能并不完全嚴(yán)格遵守 REST 架構(gòu)的所有必要約定。
RESTful Web Service 和基于SOAP的 Web Services 有著本質(zhì)的不同终娃。使用 SOAP 的 Web Service 實(shí)際上是以協(xié)議(protocol)的形式工作的味廊。因?yàn)?SOAP Web Service 嚴(yán)格規(guī)定了如何發(fā)現(xiàn)和描述 API,其傳輸?shù)南⒁灿袊?yán)格統(tǒng)一的格式(例如傳輸?shù)妮d體XML有嚴(yán)格的格式規(guī)范)棠耕。而 RESTful Web Service 并不是協(xié)議余佛,它沒(méi)有規(guī)定傳輸消息的具體格式,它只是一種約定使用 REST 架構(gòu)實(shí)現(xiàn)的 Web Service窍荧。RESTful Web Service 相比SOAP Web Service 更加簡(jiǎn)單和輕量級(jí)』匝玻現(xiàn)在大部分 RESTful Web Service 都使用類(lèi)似的形式,例如都使用HTTP傳輸蕊退,使用風(fēng)格類(lèi)似的 URL 作為 API 和 使用 JSON 或者 XML 來(lái)傳輸數(shù)據(jù)等等(目前 JSON 占據(jù)主導(dǎo)地位郊楣,并且有持續(xù)流行的趨勢(shì)[1])憔恳。
如果你之前沒(méi)有接觸過(guò)SOAP,你只需記住RESTful Web Service 是一種采用 REST 架構(gòu)約定净蚤,更簡(jiǎn)單钥组,更輕量級(jí)的Web Service
REST 之父大牛 Roy Fielding 在他的論文中,一共從下面6個(gè)方面闡述了 REST 架構(gòu)的約定(REST 應(yīng)該滿(mǎn)足哪些條件今瀑,以及這樣做會(huì)有什么好處)
REST 架構(gòu)約定
CS結(jié)構(gòu)(Client–server)
客戶(hù)端是一個(gè)相對(duì)獨(dú)立的實(shí)現(xiàn)程梦,它不必考慮數(shù)據(jù)的持久化存儲(chǔ)問(wèn)題。服務(wù)端擁有和保存數(shù)據(jù)橘荠,服務(wù)端不去關(guān)心客戶(hù)端內(nèi)部實(shí)現(xiàn)屿附,也不用關(guān)心客戶(hù)端請(qǐng)求的上下文。服務(wù)端和客戶(hù)端之間遵守相同的接口規(guī)范哥童。在遵守相同接口規(guī)范的前提下拿撩,二者都可以獨(dú)立演化,甚至可以被其它的實(shí)現(xiàn)替代如蚜。-
無(wú)狀態(tài)(Stateless)
任何時(shí)候一個(gè)客戶(hù)端的請(qǐng)求數(shù)據(jù)都包含能夠讓服務(wù)端完成請(qǐng)求的充分信息压恒,服務(wù)端不依賴(lài)前后不同請(qǐng)求的順序和狀態(tài)信息來(lái)完成請(qǐng)求。請(qǐng)求的session信息由客戶(hù)端持有错邦,并在必要時(shí)連同請(qǐng)求數(shù)據(jù)一起發(fā)送探赫。服務(wù)端可以使用請(qǐng)求中的session信息去其它外部服務(wù)或者數(shù)據(jù)庫(kù)獲取相關(guān)內(nèi)容進(jìn)以便對(duì)該請(qǐng)求做權(quán)限驗(yàn)證等操作。如果所需數(shù)據(jù)要通過(guò)多次請(qǐng)求才能完成撬呢,客戶(hù)端必須自己負(fù)責(zé)記錄狀態(tài)(因?yàn)榉?wù)器不跟蹤客戶(hù)端的狀態(tài))伦吠,在下次請(qǐng)求時(shí)附帶發(fā)出。一個(gè)典型的例子是分頁(yè)的實(shí)現(xiàn)魂拦,客戶(hù)端需要自己保存當(dāng)前頁(yè)數(shù)毛仪,請(qǐng)求下一頁(yè)時(shí)作為參數(shù)一起發(fā)給服務(wù)端,服務(wù)端使用該參數(shù)返回正確的下一頁(yè)數(shù)據(jù)芯勘。有些設(shè)計(jì)箱靴,比如Facebook API,服務(wù)端返回?cái)?shù)據(jù)中包含下一頁(yè)數(shù)據(jù)的請(qǐng)求URL荷愕,客戶(hù)端只要記錄這個(gè)URL即可發(fā)起下一頁(yè)的請(qǐng)求衡怀。
服務(wù)端不依賴(lài)客戶(hù)端的請(qǐng)求順序和狀態(tài)提高了服務(wù)器的可擴(kuò)展性(scalability)。比如在使用Load balancer的情況下安疗,不能因?yàn)槟硞€(gè)請(qǐng)求被分配到其它服務(wù)器而丟失某些信息從而返回不正確的數(shù)據(jù)抛杨。
無(wú)狀態(tài)的約定也提高了系統(tǒng)的健壯性(reliability)。如果集群服務(wù)器中的其中一臺(tái)發(fā)生故障也不會(huì)對(duì)系統(tǒng)的平穩(wěn)運(yùn)行造成太大影響荐类。不過(guò)無(wú)狀態(tài)的約定也是有缺點(diǎn)的怖现,客戶(hù)端必須每次都要帶上相同重復(fù)的信息來(lái)確定自己的身份和狀態(tài),這就造成了傳輸數(shù)據(jù)的冗余性玉罐。然而沒(méi)有一個(gè)架構(gòu)決策是十全十美的屈嗤,最終的決策往往都是相互妥協(xié)的結(jié)果潘拨,我們只能選擇一個(gè)相對(duì)有優(yōu)勢(shì)的決策。
緩存機(jī)制(Cacheable)
服務(wù)端應(yīng)該明確規(guī)定返回?cái)?shù)據(jù)的緩存機(jī)制恢共,包括是否可緩存,緩存如何失效以及利用緩存獲取增量數(shù)據(jù)而不必每次獲取全部數(shù)據(jù)等璧亚。合理的緩存設(shè)計(jì)可以減少請(qǐng)求次數(shù)讨韭,進(jìn)而提高服務(wù)器的效率和性能。系統(tǒng)分層(Layered system)
客戶(hù)端不用知道數(shù)據(jù)是從服務(wù)端直接返回還是通過(guò)中轉(zhuǎn)代理返回癣蟋。這樣的設(shè)計(jì)也同樣提高了系統(tǒng)的可擴(kuò)展性透硝。比如可以使用負(fù)責(zé)均衡和反向代理等技術(shù)來(lái)對(duì)系統(tǒng)進(jìn)行水平擴(kuò)展和緩存處理,把系統(tǒng)劃分成不同的層次疯搅。使用分層設(shè)計(jì)也方便我們管理不同資源的權(quán)限濒生,有利于提高系統(tǒng)的安全性。可定制代碼(可選)(Code on demand)
服務(wù)端可選擇臨時(shí)給客戶(hù)端下發(fā)一些功能代碼讓客戶(hù)端來(lái)執(zhí)行幔欧,從而定制和擴(kuò)展客戶(hù)端的某些功能罪治。比如服務(wù)端可以返回一些 Javascript 代碼讓客戶(hù)端執(zhí)行,去實(shí)現(xiàn)某些特定的功能礁蔗。-
一致的接口(Uniform interface)
一致的接口對(duì) REST 服務(wù)至關(guān)重要觉义。基于統(tǒng)一的接口規(guī)則可以簡(jiǎn)化系統(tǒng)實(shí)現(xiàn)浴井,降低子系統(tǒng)之間的耦合度晒骇,因?yàn)樽酉到y(tǒng)只要關(guān)注實(shí)現(xiàn)接口即可。在保證接口一致的情況下磺浙,不同的實(shí)現(xiàn)可以各自獨(dú)立演化洪囤。對(duì)于接口的要求有這么四個(gè)方面:一致的數(shù)據(jù)格式
雖然服務(wù)端內(nèi)部不同數(shù)據(jù)的存儲(chǔ)格式可能千差萬(wàn)別,但返回給客戶(hù)端的數(shù)據(jù)一定要有一個(gè)統(tǒng)一的表現(xiàn)形式撕氧。比如 Web Service 請(qǐng)求返回格式要么是 HTML瘤缩,要么是 XML,要么是 JSON伦泥,不能返回服務(wù)端自己內(nèi)部使用的特殊格式款咖。可以對(duì)已有數(shù)據(jù)進(jìn)一步操作(Resource Identifiers)
如果客戶(hù)端擁有一個(gè)資源,必要時(shí)奄喂,客戶(hù)端應(yīng)該擁有足有的信息去修改和刪除這個(gè)資源铐殃。通常我們只要在返回的數(shù)據(jù)中包含一個(gè) UID 即可做到這點(diǎn)。比如從服務(wù)端獲得了一個(gè)訂單數(shù)據(jù)跨新,這個(gè)訂單數(shù)據(jù)里應(yīng)該保證有一個(gè)唯一的訂單 ID富腊,當(dāng)我們想對(duì)這個(gè)訂單進(jìn)行進(jìn)一步操作時(shí),可以保障操作的是同一個(gè)訂單域帐。數(shù)據(jù)具有自我描述性
每項(xiàng)數(shù)據(jù)應(yīng)該是可以自我描述的赘被,方便代碼去處理和解析其中的內(nèi)容是整。比如通過(guò)HTTP返回的數(shù)據(jù)里面有 [MIME type ]信息,我們從MIME type里面可以知道數(shù)據(jù)的具體格式民假,是圖片浮入,視頻還是JSON。應(yīng)用系統(tǒng)狀態(tài)變化只依賴(lài)超媒體(Hypermedia)
應(yīng)用系統(tǒng)狀態(tài)變化只依賴(lài)于服務(wù)端發(fā)來(lái)的Hypermedia(如超鏈接 hyperlinks)羊异。舉例來(lái)說(shuō)事秀,假設(shè)向一個(gè)微博 Web Service 請(qǐng)求一條微博信息,服務(wù)端響應(yīng)信息中應(yīng)該包含和這條微博相關(guān)的其它的URL野舶∫准#客戶(hù)端可以進(jìn)一步利用這些URL發(fā)起請(qǐng)求來(lái)獲取感興趣的信息。前面章節(jié)中提到的Facebook API 可以從第一頁(yè)的返回?cái)?shù)據(jù)中獲取下一頁(yè)的URL也是基于這個(gè)設(shè)計(jì)理念平道。
REST 的這些約定為我們?cè)O(shè)計(jì) RESTful Web Service 提供了一個(gè)絕佳的范本睹欲。套用這個(gè)范本,在設(shè)計(jì) Web Service 時(shí)一屋,可以在一定程度上避免很多問(wèn)題和少走彎路窘疮。因?yàn)檫@些約定本質(zhì)上都是對(duì)現(xiàn)實(shí)系統(tǒng)設(shè)計(jì)優(yōu)點(diǎn)的一些提煉和總結(jié),它已經(jīng)比較周全的為我們考慮了可能出現(xiàn)的問(wèn)題冀墨,并且提供了解決問(wèn)題的基本原則和方向考余。
本文第三小節(jié)“REST 架構(gòu)約定”的主要內(nèi)容來(lái)自對(duì)參考文檔中的部分內(nèi)容的整理和翻譯。計(jì)算機(jī)科學(xué)有很多非常有價(jià)值的論文轧苫,很多論文是如此的重要以至于能奠定一個(gè)時(shí)代的技術(shù)基礎(chǔ)(比如 Google 的 MapReduce楚堤,可能需自備梯子)。我們只有充分理解了其中的思想和原則才能作出更好的設(shè)計(jì)和架構(gòu)含懊。
下一篇文章我們將結(jié)合HTTP的特性身冬,探討如何設(shè)計(jì) RESTful Web Service API
參考文檔
-
這個(gè)結(jié)論來(lái)自Goolge Trends(須自備梯子): https://www.google.com/trends/explore?date=all&q=xml%20api,json%20api ?