深入淺出REST架構(gòu)風(fēng)格

REST是Roy Fielding博士在他的畢業(yè)論文中首先提出來(lái)的。Roy Fielding何許人也?他是HTTP協(xié)議的主要設(shè)計(jì)者溉浙,是Apache Web Server的作者,是Apache軟件基金會(huì)的聯(lián)合創(chuàng)始人。所以他的論文一問(wèn)世颅湘,就引起了業(yè)界普遍的重視。在這篇論文里栗精,他總結(jié)了Web闯参,作為全世界最大的分布式系統(tǒng),之所以能成功的經(jīng)驗(yàn)悲立,也就是REST架構(gòu)風(fēng)格鹿寨。

時(shí)至今日,REST這個(gè)術(shù)語(yǔ)被廣泛使用薪夕。要是你到現(xiàn)在還沒(méi)聽(tīng)過(guò)REST脚草,你可以去一邊兒rest去了……不過(guò),雖然REST這個(gè)術(shù)語(yǔ)被廣泛使用原献,但是很多人對(duì)其的了解都是很模糊的馏慨。本文從REST架構(gòu)風(fēng)格的起源、REST的特點(diǎn)姑隅、REST實(shí)現(xiàn)要點(diǎn)等多個(gè)方面写隶,來(lái)探討一下,究竟REST為何物讲仰。

一慕趴、什么是架構(gòu)風(fēng)格

要了解“REST架構(gòu)風(fēng)格”,我們得先知道什么是"架構(gòu)風(fēng)格"鄙陡。

說(shuō)到風(fēng)格冕房,先來(lái)看看我們熟悉的服裝風(fēng)格:


是什么形成了這些服裝風(fēng)格,讓人一眼就能分辨出它們呢趁矾?——這是因?yàn)檫@些服裝的設(shè)計(jì)滿足了一組設(shè)計(jì)約束毒费。比如“韓版”色彩要清新、“嘻哈”造型要寬大愈魏、“朋克”要黑色加釘子質(zhì)感觅玻。滿足了這些約束想际,就會(huì)形成服裝風(fēng)格,同時(shí)也具備這些風(fēng)格所帶來(lái)的特點(diǎn)溪厘,比如“韓版”潮胡本、“嘻哈”隨性、“朋克”酷……

類似地畸悬,架構(gòu)風(fēng)格就是一組架構(gòu)的約束侧甫,滿足了這些約束,就可以具備一系列架構(gòu)的屬性蹋宦,比如可伸縮性披粟、簡(jiǎn)單性、可移植性等等冷冗。架構(gòu)風(fēng)格有很多種守屉,Roy Fielding在他的論文里列舉了二十多種。這里蒿辙,我們列舉對(duì)我們理解REST有幫助的幾個(gè)架構(gòu)風(fēng)格:

  1. 客戶-服務(wù)器風(fēng)格(Client-Server拇泛,CS):這種風(fēng)格是基于網(wǎng)絡(luò)的應(yīng)用最常見(jiàn)的一種架構(gòu)風(fēng)格∷脊啵客戶端發(fā)送請(qǐng)求給服務(wù)器俺叭,服務(wù)器處理請(qǐng)求并將結(jié)果返回給客戶端。這種架構(gòu)風(fēng)格約束要求分離關(guān)注點(diǎn)泰偿。功能的適當(dāng)分離會(huì)簡(jiǎn)化服務(wù)器組件熄守,從而提高可伸縮性。這種分離也使得服務(wù)器和客戶端可以獨(dú)立演進(jìn)耗跛。

  2. 分層系統(tǒng)風(fēng)格(Layered System裕照,LS):一個(gè)分層系統(tǒng)是按照層次來(lái)組織的,每一層為在其之上的層提供服務(wù)课兄,層與層之間不能跨層訪問(wèn)(層隔離原則)牍氛。每層的關(guān)注點(diǎn)分離晨继,這樣使得層與層之間解耦烟阐,每層的組件可以獨(dú)立演進(jìn)。

不同的架構(gòu)風(fēng)格還可以組合在一起紊扬,從而生成新的風(fēng)格蜒茄。比如:

  1. 分層-客戶-服務(wù)器風(fēng)格(LayeredClient-Server,LCS):這種風(fēng)格在CS風(fēng)格的基礎(chǔ)上添加了代理(proxy)組件層和網(wǎng)關(guān)(gateway)組件層餐屎。這些額外的中間層檀葛,為系統(tǒng)添加了負(fù)載均衡、安全性檢查等功能腹缩。

  2. 客戶-無(wú)狀態(tài)-服務(wù)器風(fēng)格(Client-Stateless-Server屿聋,CSS):這種風(fēng)格在CS風(fēng)格的基礎(chǔ)添加了新的約束:服務(wù)器不允許有會(huì)話狀態(tài)空扎。從客戶端發(fā)到服務(wù)器的每個(gè)請(qǐng)求必須包含理解請(qǐng)求所需的全部信息,不能用任何保存在服務(wù)器上的上下文信息润讥。這個(gè)風(fēng)格使得系統(tǒng)具有很好的可伸縮性转锈,因?yàn)榉?wù)器不用保存多個(gè)請(qǐng)求之間的狀態(tài),請(qǐng)求可以分發(fā)到不同的服務(wù)器中進(jìn)行處理楚殿。

  3. 緩存風(fēng)格($):緩存?zhèn)€別請(qǐng)求的結(jié)果撮慨,以便可以被后面的請(qǐng)求重用。緩存風(fēng)格可以提高性能脆粥,尤其是在基于網(wǎng)絡(luò)的系統(tǒng)中砌溺。

  4. 按需代碼風(fēng)格(Code On Demand,COD):這種風(fēng)格中变隔,客戶端向服務(wù)器發(fā)送請(qǐng)求规伐,服務(wù)器會(huì)根據(jù)需要把相應(yīng)的代碼發(fā)給客戶端,然后客戶端在本地執(zhí)行這些代碼弟胀。舉個(gè)例子楷力,比如瀏覽器訪問(wèn)一個(gè)網(wǎng)站,網(wǎng)站會(huì)把js腳本發(fā)給瀏覽器孵户,瀏覽器在本地執(zhí)行這些js腳本萧朝,對(duì)網(wǎng)頁(yè)進(jìn)行渲染。按需代碼的優(yōu)點(diǎn)有:能夠?yàn)橐粋€(gè)已部署的客戶端添加功能夏哭,改善了可擴(kuò)展性和可配置性检柬;當(dāng)代碼在本地與用戶交互而不是通過(guò)遠(yuǎn)程交互時(shí),能夠得到更好的用戶可覺(jué)察性能和效率竖配;由于服務(wù)器將工作交給了客戶端何址,從而改善了服務(wù)器的可伸縮性。它的缺點(diǎn)也很明顯:它會(huì)更加復(fù)雜性进胯;在系統(tǒng)安全性方面也面臨挑戰(zhàn)用爪;如果客戶端無(wú)法信任服務(wù)器,還會(huì)帶來(lái)部署問(wèn)題胁镐。

講了這么多偎血,究竟架構(gòu)風(fēng)格有什么用呢?

  1. 可以通過(guò)架構(gòu)風(fēng)格來(lái)比較分析各種不同架構(gòu)的特點(diǎn)盯漂。因?yàn)橐环N具體架構(gòu)既包含功能屬性又包含非功能屬性颇玷,直接比較不同類型系統(tǒng)的架構(gòu)會(huì)比較困難。而架構(gòu)風(fēng)格通過(guò)忽略架構(gòu)中其余部分的偶然性細(xì)節(jié)就缆,捕獲了一種交互模式的本質(zhì)特征帖渠,更容易對(duì)不同架構(gòu)進(jìn)行對(duì)比分析。

  2. 可以指導(dǎo)具體架構(gòu)設(shè)計(jì)竭宰。一種具體的架構(gòu)其實(shí)就是特定風(fēng)格的一個(gè)實(shí)例空郊。軟件架構(gòu)設(shè)計(jì)要滿足應(yīng)用的一系列需求份招,而為滿足這些需求,就要求架構(gòu)應(yīng)該必須具有一系列的屬性(比如可伸縮性狞甚、網(wǎng)絡(luò)效率等)脾还。而架構(gòu)風(fēng)格對(duì)架構(gòu)的約束,使得架構(gòu)具備了相應(yīng)的屬性入愧,可以對(duì)具體的架構(gòu)設(shè)計(jì)提供指導(dǎo)鄙漏。

  3. 可以推導(dǎo)出新的架構(gòu)風(fēng)格。通過(guò)將多種基本風(fēng)格組合為互相協(xié)作的一個(gè)整體棺蛛,可以推導(dǎo)出新的架構(gòu)風(fēng)格怔蚌。這種新的架構(gòu)風(fēng)格會(huì)繼承基礎(chǔ)風(fēng)格的一系列架構(gòu)屬性,形成自己獨(dú)有的架構(gòu)屬性旁赊。進(jìn)而可以用新的風(fēng)格指導(dǎo)架構(gòu)設(shè)計(jì)桦踊。

二、什么是REST架構(gòu)風(fēng)格

REST架構(gòu)風(fēng)格是Roy Fielding博士總結(jié)的Web架構(gòu)背后的設(shè)計(jì)基本原理终畅。它可以由一系列基礎(chǔ)架構(gòu)風(fēng)格推導(dǎo)出來(lái)的挟阻。從空風(fēng)格開(kāi)始蒙保,通過(guò)逐步增加約束(組合基礎(chǔ)架構(gòu)風(fēng)格),最終形成REST架構(gòu)風(fēng)格,其推導(dǎo)過(guò)程如下:


推導(dǎo)過(guò)程主要用到了我們上一節(jié)所列舉的基礎(chǔ)架構(gòu)風(fēng)格赌蔑。綜合這些基礎(chǔ)架構(gòu)風(fēng)格的約束莫换,總的來(lái)說(shuō)乌奇,REST架構(gòu)風(fēng)格的約束主要有6個(gè):

  1. 客戶-服務(wù)器:通信只能由客戶端單方面發(fā)起驶鹉,表現(xiàn)為請(qǐng)求 - 響應(yīng)的形式。
  2. 無(wú)狀態(tài):通信的會(huì)話狀態(tài)(Session State)應(yīng)該全部由客戶端負(fù)責(zé)維護(hù)絮识。
  3. 分層系統(tǒng):通過(guò)限制組件的行為(即绿聘,每個(gè)組件只能“看到”與其交互的緊鄰層),將架構(gòu)分解為若干等級(jí)的層次舌。
  4. 緩存:響應(yīng)內(nèi)容可以在通信鏈的某處被緩存熄攘,以改善網(wǎng)絡(luò)效率。
  5. 統(tǒng)一接口:通信鏈的組件之間通過(guò)統(tǒng)一的接口相互通信彼念,整體的架構(gòu)得到了簡(jiǎn)化挪圾,交互的可見(jiàn)性也得到了改善。
  6. 按需代碼(可選):支持通過(guò)下載并執(zhí)行一些代碼(例如 Java Applet国拇、Flash 或 JavaScript)洛史,對(duì)客戶端的功能進(jìn)行擴(kuò)展惯殊。

其中酱吝,強(qiáng)調(diào)組件之間要有一個(gè)統(tǒng)一的接口,是REST架構(gòu)風(fēng)格區(qū)別于其他基于網(wǎng)絡(luò)的架構(gòu)風(fēng)格的核心特征土思。通過(guò)統(tǒng)一接口务热,整體的系統(tǒng)架構(gòu)得到了簡(jiǎn)化忆嗜,交互的可見(jiàn)性也得到了改善。實(shí)現(xiàn)與它們所提供的服務(wù)是解耦的崎岂,這促進(jìn)了 獨(dú)立的可進(jìn)化性捆毫。然而,付出的代價(jià)是冲甘,統(tǒng)一接口降低了效率绩卤,因?yàn)樾畔⒍际褂脴?biāo)準(zhǔn)化的形式來(lái)轉(zhuǎn)移,而不能使用特定于應(yīng)用需求的形式江醇。

由于遵循了這些約束濒憋,REST架構(gòu)風(fēng)格就獲得了相應(yīng)的架構(gòu)屬性:

  1. 可伸縮性:通過(guò)客戶-服務(wù)器、分層系統(tǒng)陶夜、無(wú)狀態(tài)等約束凛驮,使得系統(tǒng)獲得了很好的可伸縮性。
  2. 簡(jiǎn)單性:通過(guò)客戶-服務(wù)器条辟、分層系統(tǒng)黔夭、統(tǒng)一接口等約束,分離關(guān)注點(diǎn)羽嫡,使得系統(tǒng)更容易被理解和實(shí)現(xiàn)本姥。
  3. 可修改性:通過(guò)客戶-服務(wù)器、分層系統(tǒng)杭棵、統(tǒng)一接口扣草、按需代碼等約束,使得系統(tǒng)獲得了獨(dú)立進(jìn)化颜屠、動(dòng)態(tài)擴(kuò)展辰妙、可重用的能力。
  4. 網(wǎng)絡(luò)效率:關(guān)于基于網(wǎng)絡(luò)的應(yīng)用的一個(gè)有趣現(xiàn)象是甫窟,最佳的應(yīng)用性能就是不使用網(wǎng)絡(luò)密浑。通過(guò)緩存、按需代碼等約束粗井,使得系統(tǒng)可以盡可能減少網(wǎng)絡(luò)訪問(wèn)尔破,提升網(wǎng)絡(luò)效率,減少由其他約束(如無(wú)狀態(tài)浇衬、分層系統(tǒng))引入的網(wǎng)絡(luò)開(kāi)銷懒构。

三、REST架構(gòu)風(fēng)格的一個(gè)實(shí)例——Web架構(gòu)

從REST被提出的歷史也可以看出耘擂,其實(shí)現(xiàn)代互聯(lián)網(wǎng)Web架構(gòu)——這個(gè)世界上最大最成功的分布式應(yīng)用的架構(gòu)——就是REST架構(gòu)風(fēng)格的一個(gè)具體實(shí)例胆剧。

構(gòu)成Web架構(gòu)的組件有:

  • 用戶代理:如Web瀏覽器。
  • 來(lái)源服務(wù)器:如Apache httpd。是資源的權(quán)威來(lái)源秩霍。
  • 代理:如Netscape代理篙悯。一個(gè)代理組件是由客戶端選擇的中間組件,用來(lái)為其他的服務(wù)铃绒、數(shù)據(jù)轉(zhuǎn)換鸽照、性能增強(qiáng)、或安全保護(hù)提供接口封裝颠悬。
  • 網(wǎng)關(guān):也叫反向代理矮燎,如nginx。一個(gè)網(wǎng)關(guān)組件是由網(wǎng)絡(luò)或來(lái)源服務(wù)器強(qiáng)加的中間組件赔癌,用來(lái)為其他的服務(wù)漏峰、 數(shù)據(jù)轉(zhuǎn)換、性能增強(qiáng)届榄,或安全增強(qiáng)提供接口封裝浅乔。代理和網(wǎng)關(guān)之間的區(qū)別是,何時(shí)使用代理是由客戶端來(lái)決定的铝条。

為什么這些組件組合起來(lái)可以形成REST架構(gòu)風(fēng)格呢靖苇?這離不開(kāi)Web背后的三大基石:URI、HTTP班缰、超媒體贤壁。

1. URI作為資源的標(biāo)識(shí)
什么是資源?——任何能夠被命名的信息都能夠作為一個(gè)資源埠忘,比如一份文檔脾拆、一張圖片。一個(gè)資源是到一組實(shí)體概念上的映射莹妒,而不是實(shí)體本身名船。比如,“一份代碼的最新版本”這個(gè)資源旨怠,它的值是在不斷變化的渠驼;而“這份代碼的V1.0版本”這個(gè)資源,它的值是靜態(tài)的鉴腻。這兩個(gè)是截然不同的資源迷扇,即使某個(gè)時(shí)刻他們映射的實(shí)體是相同的(即V1.0版本就是最新版本)。URI就是這個(gè)資源的標(biāo)識(shí)爽哎。

對(duì)資源的這一抽象的定義使得 Web 架構(gòu)的核心功能得以實(shí)現(xiàn)蜓席。首先,它通過(guò)包含了很多信息來(lái)源而沒(méi)有人為地通過(guò)類型或?qū)崿F(xiàn)對(duì)它們加以區(qū)分课锌,從而實(shí)現(xiàn)了通用性厨内。其次,它允許引用到表述的延遲綁定,從而支持基于請(qǐng)求的性質(zhì)來(lái)進(jìn)行內(nèi)容協(xié)商隘庄。最后,它允許一個(gè)創(chuàng)作者引用一個(gè)概念而不是引用此概念的某個(gè)單獨(dú)的表述癣亚,從而使得當(dāng)表述改變時(shí)無(wú)須修改所有的現(xiàn)有鏈接(假設(shè)創(chuàng)作者使用了正確的標(biāo)識(shí)符)丑掺。

2. HTTP作為統(tǒng)一的接口
有了資源的抽象,就可以對(duì)資源的操作設(shè)定具有統(tǒng)一語(yǔ)義的接口述雾,這就是HTTP的使命街州。HTTP的統(tǒng)一接口表現(xiàn)在幾個(gè)方面:

  • 統(tǒng)一的方法:
    GET: 用于獲取資源。它既是冪等的玻孟,又是安全無(wú)副作用的唆缴。
    POST: 用于請(qǐng)求服務(wù)端創(chuàng)建一個(gè)資源。它即不是冪等的黍翎,也不是安全的面徽。
    PUT:用于客戶端創(chuàng)建或重寫(xiě)一個(gè)資源。它是冪等的匣掸,但不是安全的趟紊。
    DELETE:用于刪除資源。它是冪等的碰酝,但不是安全的霎匈。

  • 統(tǒng)一的狀態(tài)碼,如:
    200 (OK)- 如果已存在資源被更改
    201 (created)- 如果新資源被創(chuàng)建
    301(Moved Permanently)- 資源的URI已更改
    400 (bad request)- 指代壞請(qǐng)求
    404 (not found)- 資源不存在
    500 (internal server error)- 通用錯(cuò)誤響應(yīng)
    503 (Service Unavailable)- 服務(wù)當(dāng)前無(wú)法處理請(qǐng)求

  • 統(tǒng)一的控制信息送爸,如:
    Header中的Cache-Control用來(lái)控制緩存策略
    Header中的Connection用來(lái)控制是否持久連接

有了HTTP這套統(tǒng)一語(yǔ)義的接口铛嘱,Web系統(tǒng)中的各個(gè)組件,可以不再關(guān)心具體的消息內(nèi)容而工作袭厂。比如緩存服務(wù)器可以識(shí)別是GET方法墨吓,根據(jù)其即安全又冪等的特性,默認(rèn)對(duì)其進(jìn)行緩存纹磺;并且可以根據(jù)Cache-Control中指定的信息肛真,來(lái)決定緩存的策略。這套統(tǒng)一語(yǔ)義的接口使得Web系統(tǒng)間組件相互解耦爽航,整個(gè)系統(tǒng)的集成變得簡(jiǎn)單蚓让。

3. 超媒體作為資源的表述和應(yīng)用狀態(tài)的引擎
一個(gè)表述,指的是某個(gè)資源在某個(gè)特定時(shí)刻的視圖讥珍。這個(gè)視圖被編碼為一種或多種可轉(zhuǎn)移的格式历极,比如HTML、XML衷佃、JSON趟卸、MP3、JPEG等。對(duì)于一個(gè)資源的訪問(wèn)锄列,總是通過(guò)其表述方式來(lái)間接完成的图云。

Web系統(tǒng)中以超媒體作為資源的表述。超媒體最大的特征是具有超鏈接邻邮。這一簡(jiǎn)單的特性竣况,卻可以使得客戶和服務(wù)端得到的極大解耦。想象這樣一個(gè)場(chǎng)景筒严,你在淘寶上購(gòu)買商品丹泉。這個(gè)過(guò)程是這樣的:


你會(huì)發(fā)現(xiàn),在這個(gè)過(guò)程中鸭蛙,你唯一需要知道的信息只有網(wǎng)站入口摹恨,而整個(gè)購(gòu)買過(guò)程的順利進(jìn)行,完全依賴于超鏈接給你的提示娶视,每進(jìn)入一步晒哄,超鏈接都會(huì)提示你后續(xù)還能做哪些操作。你不必記住每個(gè)操作具體的API肪获,只要你能明白超媒體的“語(yǔ)義”揩晴,你就能順利完成購(gòu)買。你需要記住的東西越少贪磺,你和網(wǎng)站之間的耦合就越弱硫兰。比如這個(gè)例子中,網(wǎng)站變更"將商品加入購(gòu)物車的API“對(duì)你來(lái)說(shuō)是透明的寒锚。

我們?cè)賮?lái)看看劫映,這個(gè)過(guò)程中,網(wǎng)站的狀態(tài)是如何變化的:


在這個(gè)過(guò)程中刹前,超媒體實(shí)際上充當(dāng)了網(wǎng)站(應(yīng)用)狀態(tài)遷移的引擎泳赋,它推動(dòng)著整個(gè)應(yīng)用狀態(tài)的遷移——與傳統(tǒng)狀態(tài)機(jī)的不同之處在于,客戶端預(yù)先不知道可能的狀態(tài)和遷移喇喉,當(dāng)應(yīng)用到達(dá)一個(gè)新的狀態(tài)時(shí)祖今,接下來(lái)的狀態(tài)遷移是可被發(fā)現(xiàn)的。就像是一個(gè)尋寶的過(guò)程拣技。

再開(kāi)一下腦洞千诬,如果把整個(gè)互聯(lián)網(wǎng)看成是一個(gè)分布式應(yīng)用,而“你”是個(gè)客戶端程序膏斤,那么只要你這個(gè)客戶端能理解超媒體中的“語(yǔ)義”徐绑,就可以通過(guò)選擇超鏈接的方式,將“超媒體作為應(yīng)用狀態(tài)的引擎”莫辨,探索式的完成各種業(yè)務(wù)流程傲茄。這里毅访,你這個(gè)客戶端和分布式應(yīng)用是非常松耦合的。

小結(jié)
可以說(shuō)盘榨,Web架構(gòu)之所以能實(shí)現(xiàn)REST架構(gòu)風(fēng)格喻粹,就是因?yàn)樯鲜鋈蠡K鼈內(nèi)齻€(gè)草巡,作為粘合劑把整個(gè)系統(tǒng)的各個(gè)組件聯(lián)在了一起守呜;同時(shí),作為整個(gè)系統(tǒng)的靈魂捷犹,使得Web系統(tǒng)具有了一系列優(yōu)越性弛饭,成為世界上最大最成功的分布式應(yīng)用冕末。理解了上述Web的三大基石萍歉,也就可以理解為什么這個(gè)架構(gòu)風(fēng)格要被命名為REST(REpresentation State Transfer,表述性狀態(tài)轉(zhuǎn)移)這么古怪的名字了档桃!它含義是:以超媒體作為資源的表述枪孩,通過(guò)HTTP將這些表述轉(zhuǎn)移到客戶端,而由客戶端通過(guò)服務(wù)器在超媒體中提供的可選超鏈接藻肄,來(lái)控制服務(wù)器上應(yīng)用狀態(tài)的遷移蔑舞。總結(jié)REST最為核心的就是:將超媒體作為應(yīng)用狀態(tài)的引擎(Hypermedia As The Engine Of Application State,縮寫(xiě)HATEOAS)嘹屯。

四攻询、把Web作為建造分布式系統(tǒng)的平臺(tái)。

你當(dāng)然可以自己按照REST架構(gòu)風(fēng)格的約束州弟,重新設(shè)計(jì)一個(gè)特定的架構(gòu)钧栖。然而,作為REST風(fēng)格的親生兒子婆翔,Web架構(gòu)拯杠,已經(jīng)是一個(gè)非常成熟的架構(gòu)體系了,包含非常多高可用的中間件啃奴√杜悖基于Web來(lái)建造分布式系統(tǒng),就相當(dāng)于站在了巨人的肩膀上最蕾,不但可以享受Web強(qiáng)大而豐富的基礎(chǔ)設(shè)施依溯,還可以獲得REST架構(gòu)風(fēng)格所帶來(lái)的一系列架構(gòu)優(yōu)點(diǎn)。這何樂(lè)而不為呢瘟则?因此誓沸,現(xiàn)有的RESTful架構(gòu)基本上都是基于Web的。

要想基于Web構(gòu)建一個(gè)REST架構(gòu)風(fēng)格的系統(tǒng)壹粟,除了需要滿足服務(wù)端無(wú)狀態(tài)的約束外拜隧,最核心的就是統(tǒng)一接口的約束宿百。這個(gè)“統(tǒng)一接口”也就是我們平常所說(shuō)的RESTful API。這也是為什么我們?cè)谡務(wù)揜EST架構(gòu)實(shí)現(xiàn)的時(shí)候洪添,很多時(shí)候?qū)嶋H上討論的是RESTful API的設(shè)計(jì)垦页。

然而很多人對(duì)RESTful API的內(nèi)涵并不清楚,有的以為用HTTP傳輸就是RESTful API干奢,有的以為用URL定義的API就是RESTful API……為了評(píng)判API滿足REST架構(gòu)風(fēng)格約束要求的程度痊焊,Richardson提出了REST成熟度模型:


第0級(jí):僅使用HTTP作為傳輸方式
其特征是整個(gè)服務(wù)只使用單個(gè)的URI,并且使用單個(gè)的HTTP方法(通常是POST)忿峻。比如基于SOAP規(guī)范的各種技術(shù)(WSDL薄啥、WS-Transfer等),它們僅使用HTTP來(lái)轉(zhuǎn)移SOAP的載荷逛尚,完全忽略了HTTP其他部分垄惧。

優(yōu)缺點(diǎn):不能利用Web架構(gòu)帶來(lái)的任何益處。

第1級(jí):使用URI描述資源
其使用了很多URI來(lái)標(biāo)識(shí)資源绰寞,但是只使用單個(gè)HTTP動(dòng)詞到逊。1級(jí)服務(wù)和0級(jí)服務(wù)的主要區(qū)別在于,1級(jí)服務(wù)暴露出了很多邏輯上的資源滤钱,而0級(jí)服務(wù)將所有的交互埋入了單個(gè)(大型的觉壶、復(fù)雜的)資源。在1級(jí)服務(wù)中件缸,通常會(huì)將操作名嵌入到URI中铜靶。如http://example.com/get_users或者http://example.com/users?method=get

優(yōu)缺點(diǎn):不同的URI可以對(duì)資源進(jìn)行建模。但是由于只用一個(gè)HTTP動(dòng)詞(一般是POST)他炊,無(wú)法利用Web的緩存等中間件争剿。

第2級(jí):使用統(tǒng)一語(yǔ)意的HTTP動(dòng)詞和狀態(tài)碼
其使用了大量URI標(biāo)識(shí)資源,同時(shí)使用多個(gè)統(tǒng)一語(yǔ)義HTTP動(dòng)詞來(lái)操作資源:GET(讀扔映怼)秒梅、POST(創(chuàng)建)、PUT(更新)舌胶、DELETE(刪除)捆蜀,并且使用HTTP狀態(tài)碼來(lái)協(xié)調(diào)交互。其中幔嫂,合理使用GET具有重要的意義辆它。因?yàn)镚ET默認(rèn)是冪等并且安全的操作,這使得Web系統(tǒng)中的中間節(jié)點(diǎn)可以使用緩存機(jī)制緩存GET的結(jié)果履恩,該機(jī)制是讓目前Web運(yùn)轉(zhuǎn)如此良好的關(guān)鍵因素之一锰茉。

優(yōu)缺點(diǎn):可以利用Web的大部分基礎(chǔ)設(shè)施。由于HTTP動(dòng)詞對(duì)操作的冪等性和安全性做了嚴(yán)格的區(qū)分切心,準(zhǔn)確使用這些動(dòng)詞會(huì)使得系統(tǒng)更具健壯性飒筑。

第3級(jí):使用超媒體作為狀態(tài)轉(zhuǎn)移引擎
在第2級(jí)的基礎(chǔ)上片吊,此級(jí)服務(wù)支持“超媒體作為應(yīng)用狀態(tài)引擎”的理念。在表述中除了包含請(qǐng)求的數(shù)據(jù)协屡,還包含消費(fèi)者下一步可能感興趣的其他資源URI鏈接俏脊。超媒體控制的關(guān)鍵在于它告訴客戶端下一步能夠做什么。

優(yōu)缺點(diǎn):可以在保證客戶端不受影響的條件下肤晓,改變服務(wù)接口(通過(guò)超媒體返回的鏈接)爷贫,實(shí)現(xiàn)了客戶端和服務(wù)端的松耦合。

當(dāng)然补憾,客戶端要想理解返回的URI代表什么意思漫萄,還需要理解其“語(yǔ)義”∮遥可以通過(guò)構(gòu)建語(yǔ)義網(wǎng)絡(luò)腾务,使得客戶端根據(jù)返回的信息推斷出它的語(yǔ)義,這種方法比較復(fù)雜但可以使得客戶端和服務(wù)器足夠的解耦威酒;也可以通和客戶端事先約定好窑睁,這種方法相對(duì)簡(jiǎn)單挺峡,只是客戶端需要知道一些帶外信息葵孤,耦合性稍微高一點(diǎn)。

你們現(xiàn)在的RESTful API成熟度達(dá)到了第幾級(jí)呢橱赠?——就我觀察尤仍,我廠的API大部分還處在第1級(jí),或者第1級(jí)到第2級(jí)的路上……

小結(jié)
以Web為基礎(chǔ)狭姨,構(gòu)建REST服務(wù)宰啦,最重要的是RESTful API的設(shè)計(jì)。只有完全達(dá)到REST成熟度第2級(jí)饼拍,才能很好的利用Web架構(gòu)提供的基礎(chǔ)設(shè)施赡模;只有完全達(dá)到第3級(jí),實(shí)現(xiàn)超媒體控制师抄,才能享受REST架構(gòu)風(fēng)格帶來(lái)的好處漓柑,構(gòu)建出像Web一樣成功的分布式服務(wù)。(注:還有一個(gè)前提是叨吮,服務(wù)需要滿足無(wú)狀態(tài)的約束辆布。)

五、REST架構(gòu)的問(wèn)題

雖然REST架構(gòu)具有一系列優(yōu)點(diǎn)茶鉴,但是它也不是萬(wàn)能的锋玲,也有其自身的缺點(diǎn):

1. 統(tǒng)一接口帶來(lái)的性能損失:由于信息都使用標(biāo)準(zhǔn)化的形式來(lái)轉(zhuǎn)移,而不能使用特定于應(yīng)用需求的形式涵叮,網(wǎng)絡(luò)效率上會(huì)比較低惭蹂。

2. 緩存的存在伞插,使得一致性問(wèn)題更為突出:緩存機(jī)制可以彌補(bǔ)一些網(wǎng)絡(luò)效率。但這有引入了新問(wèn)題盾碗,客戶端獲得的數(shù)據(jù)可能是緩存了的舊數(shù)據(jù)蜂怎,而服務(wù)器又沒(méi)有主動(dòng)通知緩存更新的機(jī)制,這使得分布式系統(tǒng)的一致性問(wèn)題更加突出置尔。

除此之外杠步,由于目前REST的主要實(shí)現(xiàn)是基于HTTP的,HTTP的一些缺點(diǎn)也導(dǎo)致了一些問(wèn)題:

3. 請(qǐng)求響應(yīng)式交互榜轿,使得服務(wù)端無(wú)法通知客戶端:HTTP的設(shè)計(jì)使得服務(wù)端不具備向客戶端發(fā)起通知的能力幽歼。客戶端要想獲得最新?tīng)顟B(tài)谬盐,需要不停的向服務(wù)端發(fā)起請(qǐng)求甸私。這既浪費(fèi)網(wǎng)絡(luò)帶寬,也無(wú)法滿足高時(shí)效性的需求飞傀。

4. HTTP動(dòng)詞表達(dá)力還不足夠:目前的HTTP動(dòng)詞只能支持基本的CRUD操作皇型。并且某些情況下,用GET來(lái)獲取資源還受到URL長(zhǎng)度的限制砸烦。用這些動(dòng)詞描述完整的服務(wù)有時(shí)會(huì)有些力不從心弃鸦。目前已有一些提案,給HTTP增加一些動(dòng)詞幢痘,比如:SEARCH(搜索)唬格、INCLUDE(將資源加入到某個(gè)資源集合中并返回服務(wù)端設(shè)定的 URI)、PLACE(使用客戶端指定的 URI 向資源集合中添加資源)颜说、MERGE(通過(guò)提供的表述合并部分資源)等等购岗。

5. HTTP明文傳輸帶來(lái)的安全性問(wèn)題:HTTP使用明文傳輸,并且不驗(yàn)證報(bào)文的完整性门粪,使得報(bào)文很容被篡改喊积。而全棧使用HTTPS來(lái)解決安全性問(wèn)題,又會(huì)帶來(lái)較高的性能開(kāi)銷玄妈。

還是那句經(jīng)典:沒(méi)有銀彈乾吻。架構(gòu)設(shè)計(jì)的過(guò)程就是不停地權(quán)衡利弊得失,從中尋求一個(gè)最佳的平衡點(diǎn)的過(guò)程措近。REST對(duì)于有些場(chǎng)景可能是很好的溶弟,它的這些缺點(diǎn)影響并不大;而對(duì)于另一些應(yīng)用場(chǎng)景瞭郑,它的缺點(diǎn)可能就是不可接受的辜御。因此,在實(shí)際架構(gòu)設(shè)計(jì)過(guò)程中屈张,是否使用REST架構(gòu)擒权,還是要具體問(wèn)題具體分析袱巨,因地制宜。

參考:

  1. Roy Fielding博士論文《Architectural Styles and the Design of Network-based Software Architectures》
  2. Richardson Maturity Model
  3. 《REST In Practice》(REST實(shí)戰(zhàn))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碳抄,一起剝皮案震驚了整個(gè)濱河市愉老,隨后出現(xiàn)的幾起案子司训,更是在濱河造成了極大的恐慌珊蟀,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件觉至,死亡現(xiàn)場(chǎng)離奇詭異璧尸,居然都是意外死亡咒林,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門爷光,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)垫竞,“玉大人,你說(shuō)我怎么就攤上這事蛀序』兜桑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵徐裸,是天一觀的道長(zhǎng)遣鼓。 經(jīng)常有香客問(wèn)我,道長(zhǎng)倦逐,這世上最難降的妖魔是什么譬正? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任宫补,我火速辦了婚禮檬姥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粉怕。我一直安慰自己健民,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布贫贝。 她就那樣靜靜地躺著秉犹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稚晚。 梳的紋絲不亂的頭發(fā)上崇堵,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音客燕,去河邊找鬼鸳劳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛也搓,可吹牛的內(nèi)容都是我干的赏廓。 我是一名探鬼主播涵紊,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼幔摸!你這毒婦竟也來(lái)了摸柄?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤既忆,失蹤者是張志新(化名)和其女友劉穎驱负,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體患雇,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡电媳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庆亡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匾乓。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖又谋,靈堂內(nèi)的尸體忽然破棺而出拼缝,到底是詐尸還是另有隱情,我是刑警寧澤彰亥,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布咧七,位于F島的核電站,受9級(jí)特大地震影響任斋,放射性物質(zhì)發(fā)生泄漏继阻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一废酷、第九天 我趴在偏房一處隱蔽的房頂上張望瘟檩。 院中可真熱鬧,春花似錦澈蟆、人聲如沸墨辛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)睹簇。三九已至,卻和暖如春寥闪,著一層夾襖步出監(jiān)牢的瞬間太惠,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工疲憋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凿渊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嗽元,于是被迫代替她去往敵國(guó)和親敛纲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 一說(shuō)到REST剂癌,我想大家的第一反應(yīng)就是“啊淤翔,就是那種前后臺(tái)通信方式∨骞龋”但是在要求詳細(xì)講述它所提出的各個(gè)約束旁壮,以及如...
    時(shí)待吾閱讀 3,415評(píng)論 0 19
  • REST本身是一個(gè)高度抽象化的架構(gòu)風(fēng)格,因而總是很難對(duì)它有一個(gè)比較深入且印象深刻的理解谐檀。寫(xiě)這篇文章的目的抡谐,是自己對(duì)...
    vito1994閱讀 2,832評(píng)論 0 26
  • 轉(zhuǎn)自 REST 協(xié)議的認(rèn)識(shí) 客戶端服務(wù)端例子 1、協(xié)議介紹:轉(zhuǎn) http://blog.csdn.net/colo...
    ZMJun閱讀 2,210評(píng)論 1 2
  • 理解RESTful架構(gòu) RESTful API 設(shè)計(jì)指南——阮一峰 由來(lái) 從技術(shù)架構(gòu)層面上看桐猬,Web的技術(shù)架構(gòu)包括...
    王皮皮_閱讀 5,848評(píng)論 0 11
  • 上班,路過(guò)公園,一陣香味飄過(guò)來(lái),甜絲絲的,是桂花的香味,如果不是上班要來(lái)不及,我肯定會(huì)停車循香而去,可現(xiàn)在,我只有...
    曉曉的窩閱讀 1,233評(píng)論 3 5