REST(Representational State Transfer)架構(gòu)風(fēng)格是一種世界觀,把信息提升為架構(gòu)中的一等公民。通過 REST 可以實現(xiàn)系統(tǒng)的高性能、可伸縮、通用性、簡單性、可修改性和可擴(kuò)展等特性。這篇文章解釋了主要的 HTTP 操作,對 HTTP 響應(yīng)碼進(jìn)行描述,并列舉相關(guān)開發(fā)庫和框架。此外,本文還提供了額外的資源,對每個主題進(jìn)行了更深入的探討。 1. 簡介REST 架構(gòu)風(fēng)格不是一種可以購買的技術(shù),也不是一個可以添加到軟件開發(fā)項目中的開發(fā)庫。首先也是最重要的,REST 是一種世界觀,把將信息提升為構(gòu)建架構(gòu)中的一等公民。 Roy Fielding 的博士論文“架構(gòu)風(fēng)格和基于網(wǎng)絡(luò)的軟件架構(gòu)設(shè)計”介紹和整理了“RESTful”系統(tǒng)的思想和相關(guān)術(shù)語。這是一篇學(xué)術(shù)論文,雖然使用正式語言,但是仍然易于理解并且提供了實踐基礎(chǔ)。 總結(jié)一下,RESTful 通過體系結(jié)構(gòu)的特定選擇能從部署的系統(tǒng)中獲得理想特性。盡管這種風(fēng)格定義的約束細(xì)節(jié)并沒有為所有場合設(shè)計,但是的確可以廣泛適用。 由于 Web 對消費者偏好有多重影響,REST 風(fēng)格的倡導(dǎo)者鼓勵企業(yè)組織在其邊界內(nèi)使用相同原則,就像他們在面向外部客戶的網(wǎng)頁上做的那樣。本文將討論現(xiàn)代 REST Web 實現(xiàn)中的基本約束和屬性。 1.1 基礎(chǔ)概念REST 表示什么含義?以無狀態(tài)方式傳輸、訪問和操作文本數(shù)據(jù)。當(dāng)正確部署后,REST 為互聯(lián)網(wǎng)上不同應(yīng)用程序之間提供了一致的互操作性。無狀態(tài)(stateless)這個術(shù)語至關(guān)重要,它使得應(yīng)用程序可以用不可知的方式進(jìn)行通信。RESTful API 通過統(tǒng)一資源定位符地址(URL)公開服務(wù)。URL 名稱將資源的區(qū)分為接受內(nèi)容或返回內(nèi)容。RFC 1738中定義了 URL scheme,可以在這里找到: https://tools./rfc/rfc1738.txt RESTful URL 類似于下面這個 library API: http:///library 實際公開的不一定是某種任意的服務(wù),而是代表對消費者有價值的信息資源。URL 作為資源句柄,可以請求、更新或刪除內(nèi)容。 開始把服務(wù)發(fā)布到某個地方,然后開始與 REST 服務(wù)進(jìn)行交互。返回的內(nèi)容可能是 XML、JSON 格式,或者更確切地說是像 Atom 或自定義 MIME 類型等超媒體格式。雖然一般建議盡可能重用現(xiàn)有的格式,但是對正確設(shè)計的媒體類型正在變得越來越寬容。 需要請求資源的時候,客戶機(jī)會發(fā)一個超文本傳輸協(xié)議(HTTP)GET 請求,例如在瀏覽器中鍵入一個 URL 然后點擊回車,選擇書簽,或者點擊錨引用鏈接。 通過編程方式與 RESTful API 交互,有數(shù)十個客戶端 API 或工具可供選擇。使用 curl 命令行工具,可以輸入以下命令:
上面的命令使用默認(rèn)格式,但你可能不需要這種格式的信息。幸運的是 HTTP 有一種機(jī)制,可以指定返回信息的格式。在請求中指定 'Accept' 頭,如果服務(wù)器支持這種格式,會以指定的格式返回。這個過程稱為內(nèi)容協(xié)商,這是 HTTP 中未被充分利用的功能之一,可以使用一個類似于上面例子中的 curl 命令來指定: $ curl –H 'Accept:application/json' http:///library 由于資源名稱與內(nèi)容格式是獨立的,從而讓請求不同格式信息成為可能。雖然 REST 中的 “R” 的含義是 “表現(xiàn)”而非“資源”,但是應(yīng)該在構(gòu)建系統(tǒng)時允許客戶端指定請求的內(nèi)容格式,請牢記這一點。在我們的例子中 library API 可能包含以下 URL:
就圖書館用戶而言,上面提到的這些 URL 可能就是只讀的,但是圖書館員使用應(yīng)用程序時實際上可以操作這些資源。 例如添加一本新書,可以向 main/book 地址 POST 一個 XML。 使用 curl 提交,看起來可能像這樣:
此時,服務(wù)器可能會對提交的內(nèi)容進(jìn)行校驗,創(chuàng)建與圖書相關(guān)的記錄,并返回響應(yīng)代碼201——表示已創(chuàng)建新資源。新資源的 URL 可以在響應(yīng)的 Location 頭中找到。 RESTful 請求一個重要特性:每次請求都包含了充足的狀態(tài)信息來響應(yīng)請求。這為服務(wù)器的可見性和無狀態(tài)創(chuàng)造了條件,并為擴(kuò)展系統(tǒng)和識別發(fā)送的請求內(nèi)容提供了理想特性。對于緩存結(jié)果也非常有幫助。服務(wù)器地址和請求狀態(tài)組合成可計算的 hash 鍵值,并形成一個結(jié)果集: http:// /book/isbn/978-0596801687 接下來我們會先介紹 GET 請求??蛻舳嗽谛枰獣r發(fā)出 GET 請求獲取指定資源??蛻舳丝梢栽诒镜鼐彺嬲埱蠼Y(jié)果,服務(wù)器可以在遠(yuǎn)程緩存結(jié)果,系統(tǒng)的中間層可以在請求鏈路中間緩存結(jié)果。這是一個與具體應(yīng)用程序無關(guān)的特性,可以加入系統(tǒng)設(shè)計中。 正因為可以操作資源,也就意味著并不是每個人都可以這樣做。我們完全可以建立一個防護(hù)模型,要求用戶在操作前驗證身份,證明他們具有該操作的授權(quán)。在本文的最后,將提供一些提升 RESTful 服務(wù)安全性的內(nèi)容。 2. REST 和 SOAP 比怎么樣?
把 REST 與 SOAP 劃等號是錯誤的。在這兩者之間進(jìn)行比較,帶來的困擾遠(yuǎn)多于好處。簡單來說,它們不是一回事。盡管可以用這兩種方法解決許多架構(gòu)問題,但是它們不能相互替換。 這種混淆很大程度上源于對 “REST 是通過 URL 調(diào)用 Web 服務(wù)”這句話的誤解。這種觀點與 RESTful 架構(gòu)的功能相距甚遠(yuǎn)。如果不全面深入理解 RESTful 的架構(gòu)實現(xiàn),就很容易誤解 REST 實踐的本意。 利用 REST 的最佳方式,是將生產(chǎn)和消費過程中的信息與技術(shù)分離實現(xiàn)解耦,進(jìn)而更好地管理系統(tǒng),讓架構(gòu)具備以下特性:
這并不是說,基于 SOAP 構(gòu)建的系統(tǒng)不能具備上述特性。而是當(dāng)技術(shù)、組織或過程的復(fù)雜性造成不能在單個事務(wù)中完成請求的生命周期時,這種情況 SOAP 能夠發(fā)揮最佳效果。 3. Richardson 成熟度模型Leonard Richardson 引入了一種成熟度模型,部分闡述了 SOAP 與 REST 之間的區(qū)別,并提供一種對不同類型的系統(tǒng)進(jìn)行分類的框架。許多人不恰當(dāng)?shù)胤Q之為 “REST”??梢詫⑦@種分類看作系統(tǒng)中不同 Web 技術(shù)組件緊密程度的度量標(biāo)準(zhǔn):包括信息資源、HTTP 作為應(yīng)用層協(xié)議和作超媒體作為控制媒介。 稱其為“成熟度模型”似乎意味著應(yīng)該只構(gòu)建“成熟度”最高的系統(tǒng)。這種看法是不合適的。第2級是有價值的,從2級向3級轉(zhuǎn)變通常只是采用了一種新的 MIME 類型。然而,從0級到3級的轉(zhuǎn)變要困難得多,因此增量式升級轉(zhuǎn)變通常也會增值。 首先,確定希望公開哪些信息資源。采用 HTTP 作為處理這些信息資源的應(yīng)用協(xié)議,包括內(nèi)容協(xié)商。接下來,當(dāng)一切就緒時,使用基于超媒體的 MIME 類型,這樣就可以充分享受 REST 的好處了。 4. 動詞動詞是用來與服務(wù)器資源交互的方法或操作。 RESTful 系統(tǒng)中有限的動詞讓剛接觸該的使用者感到困惑和沮喪。看似武斷和不必要的約束,目的是鼓勵以應(yīng)用程序無關(guān)的形式提供可預(yù)測的行為。通過明確、清晰地定義這些動詞的行為,客戶端可以在網(wǎng)絡(luò)中斷或故障時自主處理。 精心設(shè)計的 RESTful 系統(tǒng)主要使用4個 HTTP 動詞。 4.1 GETGET 請求是最常用的 Web 動詞。 GET 請求將命名資源從服務(wù)器傳輸?shù)娇蛻舳?。盡管客戶端不需要知道請求的資源內(nèi)容,但是請求返回的結(jié)果是帶元數(shù)據(jù)標(biāo)記的字節(jié)流,這表明客戶端應(yīng)該知道如何解釋資源。 在 Web 中通常用 “text/html” 或 “application/xhtml xml” 表示。正如之前提到的那樣,只要服務(wù)器支持,客戶端可以通過內(nèi)容協(xié)商提前指定請求的返回格式。 GET 請求關(guān)鍵點之一,不要修改服務(wù)器端的任何內(nèi)容。這是一個基本的安全要求,也是不熟悉 REST 的開發(fā)者犯的最大錯誤之一。你可能會遇到這樣的 URL:
不要這樣做! 由于 GET 請求安全性允許緩存請求,這會讓正在構(gòu)建的 RESTful 系統(tǒng)陷入混亂。 GET 請求也意味著冪等性,即多次請求不會對系統(tǒng)產(chǎn)生任何影響。這是基于分布式基礎(chǔ)設(shè)施的一個重要特性。如果進(jìn)行 GET 請求時被打斷,由于冪等性,客戶端可以再次發(fā)起請求。這點非常重要。在設(shè)計良好的基礎(chǔ)結(jié)構(gòu)中,客戶端可以從任意應(yīng)用程序發(fā)起請求。雖然一定會有與應(yīng)用程序相關(guān)的特定行為,但是加入與應(yīng)用程序無關(guān)的行為越多,系統(tǒng)就會越有彈性,也更容易維護(hù)。 4.2 POST在辨別 POST 和 PUT 動詞意圖的時候,情況開始變得不那么清晰。根據(jù)定義,二者似乎都可以被客戶端用來創(chuàng)建或更新服務(wù)器資源,然而它們的用途各有不同。 當(dāng)無法預(yù)測請求創(chuàng)建的資源的標(biāo)識時,客戶端會使用 POST 請求。在新增雇員、下訂單或提交表單的時候,我們無法預(yù)測服務(wù)器將如何命名正在創(chuàng)建的資源。這就是為什么將資源提交給類似 Servlet 這樣的程序處理。接下來,服務(wù)器會接受請求、校驗請求、驗證用戶憑據(jù)等。成功處理后,服務(wù)器將返回 201 HTTP 響應(yīng)代碼,其中包含一個 “Location” 頭,代表新創(chuàng)建的資源的位置。 注意: 有些人將 POST 視為創(chuàng)建資源的 GET 會話。他們會對創(chuàng)建的資源通過 body 返回200,而不是返回201。這似乎是避免二次請求的一種快捷方式,但是這種做法混合了 POST 和 GET,讓緩存資源的潛在影響變得微妙。盡量避免因為走捷徑而犧牲大局。短期看這似乎是值得的,但隨著時間的推移,這些捷徑疊加起來可能會帶來不利的影響。 POST 動詞的另一個主要用途是“追加(Append)”資源信息,即增量編輯或部分更新,而不是提交完整的資源。這里應(yīng)使用 PUT 操作。對已知資源使用 POST 更新,可用于向訂單添加新送貨地址或更新購物車中某個商品的數(shù)量。 由于是更新資源的部分信息,POST 既不安全也不冪等。 POST 的最后一種常見用法是提交查詢。將查詢的內(nèi)容或表單內(nèi)容進(jìn)行 URL 編碼后提交給服務(wù)執(zhí)行查詢。通??梢灾苯臃祷?POST 結(jié)果,因為沒有與查詢相關(guān)的標(biāo)識。 注意: 建議將這樣的查詢轉(zhuǎn)換為信息資源本身。如果采用 POST 查詢,可以考慮采用 GET 請求,后者支持緩存。你可以與其他人分享這個鏈接。 4.3 PUT由于 HTML 表單目前還不支持 PUT,許多開發(fā)人員基本上會忽略 PUT 動詞。然而,PUT 有一個重要作用并且是 RESTful 系統(tǒng)完整愿景的一部分。 客戶端可以向指定 URL 發(fā) PUT 請求,服務(wù)器用請求中的數(shù)據(jù)執(zhí)行覆蓋操作。PUT 請求在某種程度上是等冪的,而 POST 更新不是。 如果客戶端在 PUT 覆蓋請求時被打斷,由于重新發(fā)送覆蓋操不會造成任何后果,因此可以再次發(fā)送??蛻舳司邆涔芾頎顟B(tài)能力,所以直接重發(fā)覆蓋命令即可。 注意: 這種協(xié)議層處理并不意味著要取消更高級別(如應(yīng)用層)的事務(wù),但是同樣地,它也是一種體系結(jié)構(gòu)上理想的屬性,可以在應(yīng)用層以下使用。 如果客戶端能夠提前了解資源的標(biāo)識,那么 PUT 也可用于創(chuàng)建資源。正如我們在 POST 部分中討論的那樣,通常不會出現(xiàn)這種情況。但是如果客戶端能夠控制服務(wù)器端信息空間,那么這種操作也是合理的。 4.4 DELETE在公共網(wǎng)絡(luò)上 DELETE 動詞沒有被廣泛使用(謝天謝地!)。然而,對于控制信息空間非常有用,它是資源生命周期中非常有用的一部分。 DELETE 請求意在實現(xiàn)等冪??赡苡捎诰W(wǎng)絡(luò)故障 DELETE 請求被打斷,這時我們希望客戶端繼續(xù)嘗試。第一次請求無論成功與否,資源都應(yīng)該返回204(無指定內(nèi)容)。對之前已刪除的資源或不存在的資源可能需要一些額外處理,兩種情況都應(yīng)該返回404。一些安全策略要求為不存在的和已刪除的資源返回404,這樣 DELETE 請求就不會泄漏有關(guān)資源是否存在的信息。 還有另外三個沒有廣泛使用但是有價值的動詞。 4.5 HEADHEAD 動詞用來請求資源,但不實際檢索。客戶端可以通過 HEAD 檢查資源是否存在,并檢查資源相關(guān)的元數(shù)據(jù)。 4.6 OPTIONSOPTIONS 動詞也可以用來查詢服務(wù)器相關(guān)資源的情況,方法是詢問哪些其它動詞可用于該資源。 4.7 PATCH最新的動詞 PATCH 直到2010年才正式采納為 HTTP 的一部分。旨在提供一種標(biāo)準(zhǔn)化方式來表示部分更新。PATCH 請求通過標(biāo)準(zhǔn)格式讓交互的意圖更明確。這是推薦使用 PATCH 而非 POST 的原因,盡管 POST 可以用于任何事情。 IETF 發(fā)布了 RFC 文檔,定義用于 PATCH 操作的 XML 和 JSON。 如果客戶端 PATCH 請求的 header 中帶 If-Match,則此部分為冪等更新??梢灾卦囍袛嗟恼埱螅驗槿绻谝淮握埱蟪晒?,那么 If-Match header 會不同于新狀態(tài)。如果相同,則未處理原始請求可應(yīng)用 PATCH。 5. 響應(yīng)碼HTTP 響應(yīng)碼為我們在客戶端和服務(wù)器之間的對話提供了豐富的請求狀態(tài)信息。大多數(shù)人只熟悉一般意義上的200、403、404或者500,但是還有更多有用的代碼可供使用。這里表格并不全面,但是它們涵蓋了許多在 RESTful 環(huán)境中應(yīng)該考慮使用的最重要代碼。數(shù)字可按照以下類別分組:
第一組響應(yīng)碼表明客戶端的請求格式正確且處理成功。具體操作如下表所示: 表1 成功的客戶端請求 表2 — 客戶端重定向請求 表3中的響應(yīng)代碼表示客戶端請求無效,如果條件不發(fā)生變化,重新請求仍無法處理。這些故障可能有請求格式錯誤、未授權(quán)的請求、請求的資源不存在等。 表3 客戶端請求錯誤 最后,表4中的響應(yīng)代碼表示服務(wù)器暫時無法處理客戶端請求(可能仍然無效)??蛻舳藨?yīng)當(dāng)在將來的某個時候重新請求。 表4 服務(wù)器處理請求錯誤 服務(wù)根據(jù)其自身功能要求具有不同程度的可擴(kuò)展性。 注意: 試試響應(yīng)代碼418,它會返回簡潔有力的回復(fù):'我是一個茶壺。' 5.1 REST 資源5.1.1 論文Fielding 博士的論文《架構(gòu)的風(fēng)格與基于網(wǎng)絡(luò)的軟件架構(gòu)設(shè)計》是對 RESTful 思想的主要介紹:http://www.ics./~fielding/pubs/dissertation/top.htm 5.1.2 RFC 規(guī)范REST 常見用法的技術(shù)規(guī)范由**國際互聯(lián)網(wǎng)工程任務(wù)組(IETF)定義,按照請求評議(RFC)**流程完善。規(guī)范由數(shù)字定義,并隨著時間推移不時更新版本,以替換已經(jīng)過時的文件。目前,這里有最新的相關(guān) RFC 文件。 5.1.2.1 URIRFC 3986定義了 URI 命名方案的通用語法。URI 是一種命名方案,包含了對其他如網(wǎng)址、支持名字子空間等編碼方案。網(wǎng)址:http://www./rfc/rfc3986.txt> 5.1.2.2 URLUrl 是 URI 的一種形式,其中嵌入了充足的信息(通常是訪問方案和地址),用于解析和定位資源統(tǒng)一資源定位符。 網(wǎng)址:http://www./rfc/rfc1738.txt 5.1.2.3 IRI國際化資源標(biāo)識符(IRI)在概念上是一個用 Unicode 編碼的 URI,用于在 Web 上使用的標(biāo)識符中支持世界上各種語言的字符。 IETF 選擇創(chuàng)建一個新的標(biāo)準(zhǔn),而不是改變 URI 方案本身,以避免破壞現(xiàn)有的系統(tǒng)并明確區(qū)分這兩種方法。那些支持 IRI 的人故意這樣做。 還定義了在 IRI 和 URI 之間進(jìn)行轉(zhuǎn)換的映射方案。 網(wǎng)址<:http://www./rfc/rfc3987.txt 5.1.2.4 HTTPHTTP 1.1版本定義了一個應(yīng)用程序協(xié)議,用于操作通常以超媒體格式表示的信息資源。雖然它是一個應(yīng)用級協(xié)議,但通常不與應(yīng)用程序綁定,由此產(chǎn)生了重要的體系結(jié)構(gòu)優(yōu)勢。 大多數(shù)人認(rèn)為 HTTP 和超文本標(biāo)記語言文(HTML)就是“Web”,但是 HTTP 在非面向文檔的系統(tǒng)開發(fā)中也很有用。 網(wǎng)址: http://www./rfc/rfc2616.txt 5.1.2.5 PATCH 格式JavaScript 對象表示法(JSON)Patch 網(wǎng)址:https://www./rfc/rfc6902.txt 5.2 描述語言人們對使用各種語言來描述 API 非常感興趣,通過描述語言可以更容易地編寫客戶端和服務(wù)器文檔,甚至生成骨架代碼。一些比較流行、有趣的描述語言包括: 5.2.1 RAMLRAML 是一種 YAML/JSON 語言,可以定義2級成熟度的 API。它支持可重用模式和特性,通過模式和特性實現(xiàn)功能 API 設(shè)計的標(biāo)準(zhǔn)化。網(wǎng)址:http:// 5.2.2 SwaggerSwagger 是另一種 YAML/JSON 語言,支持定義2級成熟度的 API。它包含代碼生成器、編輯器、 API 文檔可視化功能,能夠與其他服務(wù)集成的。 網(wǎng)址:http:// 5.2.3 Apiary.ioApiary.io 是一個協(xié)作式的托管站點。它支持 Markdown 格式的 API 文檔,可以圍繞設(shè)計過程進(jìn)行社交,并且支持模擬數(shù)據(jù)的托管實現(xiàn),以便于在 API 實現(xiàn)之前對其進(jìn)行測試。 網(wǎng)址:http:// 5.2.4 Hydra-CgHydra-Cg 是一種超媒體描述語言,通過像 JSON-LD 這樣的標(biāo)準(zhǔn)方便地實現(xiàn)數(shù)據(jù)關(guān)聯(lián)和并其它數(shù)據(jù)源的交互。網(wǎng)址:http://www. 5.3 實現(xiàn)有一些用于構(gòu)建、生成和使用 RESTful 系統(tǒng)的庫和框架。雖然任何 Web 服務(wù)器都可以配置成提供 REST API,但有了這些框架、庫和環(huán)境可以讓過程變得更容易。 以下概述了一些主流的環(huán)境: 5.3.1 JAX-RSJAX-RS 規(guī)范為 JEE 環(huán)境增加了對 REST 的支持。網(wǎng)址:https://jax-rs-spec. 5.3.2 RestletRestlet API 是構(gòu)建用于生產(chǎn)和消費 RESTful 系統(tǒng)的 Java API 先行者之一。它專注于為客戶端和服務(wù)器生成一些非常干凈、強(qiáng)大的 API。 Restlet Studio 是一個免費工具,能夠在 RAML 和基于 swagger 的 API 描述之間進(jìn)行轉(zhuǎn)換,支持 Restlet、 Node 和 JAX-RS 服務(wù)器和客戶端的骨架和 Stub 代碼。網(wǎng)址:http:// 5.3.3 NetKernelNetkernel 是一個比較有趣的 RESTful 系統(tǒng)。它基于微內(nèi)核,是支持各種架構(gòu)風(fēng)格環(huán)境的代表。Netkernel 受益于在軟件體系結(jié)構(gòu)中采用 Web 的經(jīng)濟(jì)屬性。你可以把它想象成“在內(nèi)部引入 REST”。雖然任何基于 REST 的系統(tǒng)在外面看起來都一樣,但在運行環(huán)境內(nèi)部 NetKernel 看起來也一樣。網(wǎng)址:http:// 5.3.4 Play兩個主要的 Scala REST 框架之一。網(wǎng)址:https://www. 5.3.5 Spray兩個主要的 Scala REST 框架之一。它設(shè)計成配合 Akka actor 模型一起工作。網(wǎng)址:http:// 5.3.6 Express兩個主要的 Node.js REST 框架之一。網(wǎng)址:http:// 5.3.7 hapi兩個主要的 Node.js REST 框架之一。網(wǎng)址:http:// 5.3.8 SinatraSinatra 是一個領(lǐng)域特定語言(DSL),用來在 Ruby 中創(chuàng)建 RESTful 應(yīng)用程序。網(wǎng)址:http://www. 5.4 客戶端通過瀏覽器調(diào)用 REST API 是可行的,但是還有其它客戶端可用于測試和構(gòu)建面向資源的系統(tǒng)。 5.4.1 curlcurl 是流行的庫和命令行工具之一,支持在各種資源上調(diào)用各種協(xié)議。網(wǎng)址:https://curl. 5.4.2 httpiehttpie 是一個非常靈活和易用的客戶端,支持通過 HTTP 與資源進(jìn)行交互。網(wǎng)址:https:// 5.4.3 Postman健全的 API 測試需要能夠捕獲和重播請求,支持各種身份驗證和授權(quán)方案等功能。以前的命令行工具允許這樣做,但 Postman 是一個較新的桌面應(yīng)用程序,讓這些工作對于開發(fā)團(tuán)隊來說變得更容易。網(wǎng)址:https://www. 6. 書籍
|
|