本真的REST架構(gòu)風(fēng)格理解
引子
在移動(dòng)互聯(lián)網(wǎng)、云計(jì)算迅猛發(fā)展的今天,作為一名Web 開(kāi)發(fā)者,如果您還沒(méi)聽(tīng)說(shuō)過(guò)“REST”這個(gè)buzzword,顯然已經(jīng)落伍了??鋸堻c(diǎn)說(shuō),甚至“出了門(mén)都不好意思跟別人打招呼”。盡管如此,對(duì)于REST 這個(gè)泊來(lái)品的理解,大多數(shù)人(包括一些資深的架構(gòu)師)仍然停留在“盲人摸象”的階段。常常聽(tīng)到各種各樣關(guān)于REST 的說(shuō)法,例如:有人說(shuō):“我們這套新的API 決定不用Web Service(SOAP+WSDL),而是直接使用HTTP+JSON,也就是用RESTful 的方式來(lái)開(kāi)發(fā)。” 不用SOAP,甚至也不用XML,就自動(dòng)變成了RESTful 了。還有人認(rèn)為:REST 與傳統(tǒng)的Web Service 其實(shí)沒(méi)有本質(zhì)區(qū)別,只是對(duì)于URI 的構(gòu)造方式提出了更多要求,而這些要求Web Service 完全都可以實(shí)現(xiàn)。潛臺(tái)詞是:既生瑜,何生亮。Web Service 已經(jīng)足夠好了,干嘛還要再折騰什么REST。這些對(duì)于REST 的不同說(shuō)法,果真如此嗎?REST 究竟是什么?是一種新的技術(shù)、一種新的架構(gòu)、還是一種新的規(guī)范?
對(duì)于這些問(wèn)題筆者先不解答,為了深入理解REST 是什么,我們需要回顧一下Web 發(fā)展的最初年代,從源頭上講講REST 是怎么得來(lái)的。
Web 技術(shù)發(fā)展與 REST 的由來(lái)
Web(萬(wàn)維網(wǎng) World Wide Web 的簡(jiǎn)稱(chēng))是個(gè)包羅萬(wàn)象的萬(wàn)花筒,不同的人從不同的角度觀察,對(duì)于 Web 究竟是什么會(huì)得出大不相同的觀點(diǎn)。作為 Web 開(kāi)發(fā)者,我們需要從技術(shù)上來(lái)理解 Web。從技術(shù)架構(gòu)層面上看,Web 的技術(shù)架構(gòu)包括了四個(gè)基石:
- URI
- HTTP
- HyperText(除了 HTML 外,也可以是帶有超鏈接的 XML 或 JSON)
- MIME
這四個(gè)基石相互支撐,促使 Web 這座宏偉的大廈以幾何級(jí)數(shù)的速度發(fā)展了起來(lái)。在這四個(gè)基石之上,Web 開(kāi)發(fā)技術(shù)的發(fā)展可以粗略劃分成以下幾個(gè)階段:
- 靜態(tài)內(nèi)容階段:在這個(gè)最初的階段,使用 Web 的主要是一些研究機(jī)構(gòu)。Web 由大量的靜態(tài) HTML 文檔組成,其中大多是一些學(xué)術(shù)論文。Web 服務(wù)器可以被看作是支持超文本的共享文件服務(wù)器。
- CGI 程序階段:在這個(gè)階段,Web 服務(wù)器增加了一些編程 API。通過(guò)這些 API 編寫(xiě)的應(yīng)用程序,可以向客戶(hù)端提供一些動(dòng)態(tài)變化的內(nèi)容。Web 服務(wù)器與應(yīng)用程序之間的通信,通過(guò) CGI(Common Gateway Interface)協(xié)議完成,應(yīng)用程序被稱(chēng)作 CGI 程序。
- 腳本語(yǔ)言階段:在這個(gè)階段,服務(wù)器端出現(xiàn)了 ASP、PHP、JSP、ColdFusion 等支持 session 的腳本語(yǔ)言技術(shù),瀏覽器端出現(xiàn)了 Java Applet、JavaScript 等技術(shù)。使用這些技術(shù),可以提供更加豐富的動(dòng)態(tài)內(nèi)容。
- 瘦客戶(hù)端應(yīng)用階段:在這個(gè)階段,在服務(wù)器端出現(xiàn)了獨(dú)立于 Web 服務(wù)器的應(yīng)用服務(wù)器。同時(shí)出現(xiàn)了 Web MVC 開(kāi)發(fā)模式,各種 Web MVC 開(kāi)發(fā)框架逐漸流行,并且占據(jù)了統(tǒng)治地位?;谶@些框架開(kāi)發(fā)的 Web 應(yīng)用,通常都是瘦客戶(hù)端應(yīng)用,因?yàn)樗鼈兪窃诜?wù)器端生成全部的動(dòng)態(tài)內(nèi)容。
- RIA 應(yīng)用階段:在這個(gè)階段,出現(xiàn)了多種 RIA(Rich Internet Application)技術(shù),大幅改善了 Web 應(yīng)用的用戶(hù)體驗(yàn)。應(yīng)用最為廣泛的 RIA 技術(shù)是 DHTML+Ajax。Ajax 技術(shù)支持在不刷新頁(yè)面的情況下動(dòng)態(tài)更新頁(yè)面中的局部?jī)?nèi)容。同時(shí)誕生了大量的 Web 前端 DHTML 開(kāi)發(fā)庫(kù),例如 Prototype、Dojo、ExtJS、jQuery/jQuery UI 等等,很多開(kāi)發(fā)庫(kù)都支持單頁(yè)面應(yīng)用(Single Page Application)的開(kāi)發(fā)。其他的 RIA 技術(shù)還有 Adobe 公司的 Flex、微軟公司的 Silverlight、Sun 公司的 JavaFX(現(xiàn)在為 Oracle 公司所有)等等。
- 移動(dòng) Web 應(yīng)用階段:在這個(gè)階段,出現(xiàn)了大量面向移動(dòng)設(shè)備的 Web 應(yīng)用開(kāi)發(fā)技術(shù)。除了 Android、iOS、Windows Phone 等操作系統(tǒng)平臺(tái)原生的開(kāi)發(fā)技術(shù)之外,基于 HTML5 的開(kāi)發(fā)技術(shù)也變得非常流行。
從上述 Web 開(kāi)發(fā)技術(shù)的發(fā)展過(guò)程看,Web 從最初其設(shè)計(jì)者所構(gòu)思的主要支持靜態(tài)文檔的階段,逐漸變得越來(lái)越動(dòng)態(tài)化。Web 應(yīng)用的交互模式,變得越來(lái)越復(fù)雜:從靜態(tài)文檔發(fā)展到以?xún)?nèi)容為主的門(mén)戶(hù)網(wǎng)站、電子商務(wù)網(wǎng)站、搜索引擎、社交網(wǎng)站,再到以?shī)蕵?lè)為主的大型多人在線游戲、手機(jī)游戲。
在互聯(lián)網(wǎng)行業(yè),實(shí)踐總是走在理論的前面。Web 發(fā)展到了 1995 年,在 CGI、ASP 等技術(shù)出現(xiàn)之后,沿用了多年、主要面向靜態(tài)文檔的 HTTP/1.0 協(xié)議已經(jīng)無(wú)法滿(mǎn)足 Web 應(yīng)用的開(kāi)發(fā)需求,因此需要設(shè)計(jì)新版本的 HTTP 協(xié)議。在 HTTP/1.0 協(xié)議專(zhuān)家組之中,有一位年輕人脫穎而出,顯示出了不凡的洞察力,后來(lái)他成為了 HTTP/1.1 協(xié)議專(zhuān)家組的負(fù)責(zé)人。這位年輕人就是 Apache HTTP 服務(wù)器的核心開(kāi)發(fā)者 Roy Fielding,他還是 Apache 軟件基金會(huì)的合作創(chuàng)始人。
Roy Fielding 和他的同事們?cè)?HTTP/1.1 協(xié)議的設(shè)計(jì)工作中,對(duì)于 Web 之所以取得巨大成功,在技術(shù)架構(gòu)方面的因素做了一番深入的總結(jié)。Fielding 將這些總結(jié)納入到了一套理論框架之中,然后使用這套理論框架中的指導(dǎo)原則,來(lái)指導(dǎo) HTTP/1.1 協(xié)議的設(shè)計(jì)方向。HTTP/1.1 協(xié)議的第一個(gè)草稿是在 1996 年 1 月發(fā)布的,經(jīng)過(guò)了三年多時(shí)間的修訂,于 1999 年 6 月成為了 IETF 的正式規(guī)范(包括了 RFC 2616 以及用于對(duì)客戶(hù)端做身份認(rèn)證的 RFC 2617)。HTTP/1.1 協(xié)議設(shè)計(jì)的極為成功,以至于發(fā)布之后整整 10 年時(shí)間里,都沒(méi)有多少人認(rèn)為有修訂的必要。用來(lái)指導(dǎo) HTTP/1.1 協(xié)議設(shè)計(jì)的這套理論框架,最初是以備忘錄的形式在專(zhuān)家組成員之間交流,除了 IETF/W3C 的專(zhuān)家圈子,并沒(méi)有在外界廣泛流傳。Fielding 在完成 HTTP/1.1 協(xié)議的設(shè)計(jì)工作之后,回到了加州大學(xué)歐文分校繼續(xù)攻讀自己的博士學(xué)位。第二年(2000 年)在他的博士學(xué)位論文 Architectural Styles and the Design of Network-based Software Architectures 中,F(xiàn)ielding 更為系統(tǒng)、嚴(yán)謹(jǐn)?shù)仃U述了這套理論框架,并且使用這套理論框架推導(dǎo)出了一種新的架構(gòu)風(fēng)格,并且為這種架構(gòu)風(fēng)格取了一個(gè)令人輕松愉快的名字“REST”——Representational State Transfer(表述性狀態(tài)轉(zhuǎn)移)的縮寫(xiě)。
在筆者看來(lái),F(xiàn)ielding 這篇博士論文在 Web 發(fā)展史上的價(jià)值,不亞于 Web 之父 Tim Berners-Lee 關(guān)于超文本的那篇經(jīng)典論文。然而遺憾的是,這篇博士論文在誕生之后的將近 5 年時(shí)間里,一直沒(méi)有得到足夠的重視。例如 Web Service 相關(guān)規(guī)范 SOAP/WSDL 的設(shè)計(jì)者們,顯然不大理解 REST 是什么,HTTP/1.1 究竟是一個(gè)什么樣的協(xié)議、為何要設(shè)計(jì)成這個(gè)樣子。
這種情況在 2005 年之后有了很大的改善,隨著 Ajax、Ruby on Rails 等新的 Web 開(kāi)發(fā)技術(shù)的興起,在 Web 開(kāi)發(fā)技術(shù)社區(qū)掀起了一場(chǎng)重歸 Web 架構(gòu)設(shè)計(jì)本源的運(yùn)動(dòng),REST 架構(gòu)風(fēng)格得到了越來(lái)越多的關(guān)注。在 2007 年 1 月,支持 REST 開(kāi)發(fā)的 Ruby on Rails 1.2 版正式發(fā)布,并且將支持 REST 開(kāi)發(fā)作為 Rails 未來(lái)發(fā)展中的優(yōu)先內(nèi)容。Ruby on Rails 的創(chuàng)始人 DHH 做了一個(gè)名為“World of Resources”的精彩演講,DHH 在 Web 開(kāi)發(fā)技術(shù)社區(qū)中的強(qiáng)大影響力,使得 REST 一下子處在 Web 開(kāi)發(fā)技術(shù)舞臺(tái)的聚光燈之下。
今天,各種流行的 Web 開(kāi)發(fā)框架,幾乎沒(méi)有不支持 REST 開(kāi)發(fā)的了。大多數(shù) Web 開(kāi)發(fā)者都是通過(guò)閱讀某種 REST 開(kāi)發(fā)框架的文檔,以及通過(guò)一些例子代碼來(lái)學(xué)習(xí) REST 開(kāi)發(fā)的。然而,通過(guò)例子代碼來(lái)學(xué)習(xí) REST 有非常大的局限性。因?yàn)?REST 并不是一種具體的技術(shù),也不是一種具體的規(guī)范,REST 其實(shí)是一種內(nèi)涵非常豐富的架構(gòu)風(fēng)格。通過(guò)例子代碼來(lái)學(xué)習(xí) REST,除了學(xué)習(xí)到一種有趣的 Web 開(kāi)發(fā)技術(shù)之外,并不能全面深入的理解 REST 究竟是什么。甚至還會(huì)誤以為這些簡(jiǎn)單的例子代碼就是 REST 本身,REST 不過(guò)是一種簡(jiǎn)單的 Web 開(kāi)發(fā)技術(shù)而已。就像盲人摸象一樣,有的人摸到了象鼻子、有的人摸到了象耳朵、有的人摸到了象腿、有的人摸到了象尾巴。他們都堅(jiān)信自己感覺(jué)到的大象,才是最真實(shí)的大象,而其他人的感覺(jué)都是錯(cuò)誤的。
對(duì)于不理解 REST 的 Web 開(kāi)發(fā)者,人們習(xí)慣于展示一些例子代碼來(lái)讓他們理解 REST,筆者不贊同上述做法。如果 Web 開(kāi)發(fā)者想要深入理解 REST 是什么,就很難避開(kāi) Fielding 的這篇博士論文。筆者在本文中對(duì)于 REST 是什么的介紹,也是基于 Fielding 的博士論文的。盡管如此,筆者強(qiáng)烈建議本文的讀者親自去通讀一下 Fielding 的博士論文,就像想要了解孔子的思想應(yīng)該直接去讀《論語(yǔ)》等著作,而不是首先去讀其他人的轉(zhuǎn)述一樣。筆者在本文中也僅僅是努力不做一個(gè)把經(jīng)書(shū)念錯(cuò)了的歪嘴和尚而已。那么,下面我們言歸正傳。
在 Fielding 的這篇名為 Architectural Styles and the Design of Network-based Software Architectures 的博士論文(中文版名為《架構(gòu)風(fēng)格與基于網(wǎng)絡(luò)的軟件架構(gòu)設(shè)計(jì)》)中,提出了一整套基于網(wǎng)絡(luò)的軟件(即所謂的“分布式應(yīng)用”)的設(shè)計(jì)方法,值得所有分布式應(yīng)用的開(kāi)發(fā)者仔細(xì)閱讀、深入體會(huì)。
在論文的前三章中,F(xiàn)ielding 在批判性繼承前人研究成果的基礎(chǔ)上,建立起來(lái)一整套研究和評(píng)價(jià)軟件架構(gòu)的方法論。這套方法論的核心是“架構(gòu)風(fēng)格”這個(gè)概念。架構(gòu)風(fēng)格是一種研究和評(píng)價(jià)軟件架構(gòu)設(shè)計(jì)的方法,它是比架構(gòu)更加抽象的概念。一種架構(gòu)風(fēng)格是由一組相互協(xié)作的架構(gòu)約束來(lái)定義的。架構(gòu)約束是指軟件的運(yùn)行環(huán)境施加在架構(gòu)設(shè)計(jì)之上的約束。
在論文的第四章中,F(xiàn)ielding 研究了 Web 這樣一個(gè)分布式系統(tǒng)對(duì)于軟件架構(gòu)設(shè)計(jì)提出了哪些需求。在第五章中,F(xiàn)ielding 將第四章 Web 提出的需求具體化為一些架構(gòu)約束,通過(guò)逐步添加各種架構(gòu)約束,推導(dǎo)出來(lái)了 REST 這種新的架構(gòu)風(fēng)格。
REST 架構(gòu)風(fēng)格的推導(dǎo)過(guò)程
圖 1:REST 所繼承的架構(gòu)風(fēng)格約束

在圖1 中,每一個(gè)橢圓形里面的縮寫(xiě)詞代表了一種架構(gòu)風(fēng)格,而每一個(gè)箭頭邊的單詞代表了一種架構(gòu)約束。
REST 架構(gòu)風(fēng)格最重要的架構(gòu)約束有 6 個(gè):
- 客戶(hù) - 服務(wù)器(Client-Server)
通信只能由客戶(hù)端單方面發(fā)起,表現(xiàn)為請(qǐng)求 - 響應(yīng)的形式。
- 無(wú)狀態(tài)(Stateless)
通信的會(huì)話狀態(tài)(Session State)應(yīng)該全部由客戶(hù)端負(fù)責(zé)維護(hù)。
- 緩存(Cache)
響應(yīng)內(nèi)容可以在通信鏈的某處被緩存,以改善網(wǎng)絡(luò)效率。
- 統(tǒng)一接口(Uniform Interface)
通信鏈的組件之間通過(guò)統(tǒng)一的接口相互通信,以提高交互的可見(jiàn)性。
- 分層系統(tǒng)(Layered System)
通過(guò)限制組件的行為(即,每個(gè)組件只能“看到”與其交互的緊鄰層),將架構(gòu)分解為若干等級(jí)的層。
- 按需代碼(Code-On-Demand,可選)
支持通過(guò)下載并執(zhí)行一些代碼(例如 Java Applet、Flash 或 JavaScript),對(duì)客戶(hù)端的功能進(jìn)行擴(kuò)展。
在論文中推導(dǎo)出的 REST 架構(gòu)風(fēng)格如下圖所示:
圖 2:REST 架構(gòu)風(fēng)格

而HTTP/1.1 協(xié)議作為一種REST 架構(gòu)風(fēng)格的架構(gòu)實(shí)例,其架構(gòu)如下圖所示:
圖3:一個(gè)基于REST 的架構(gòu)的過(guò)程視圖

用戶(hù)代理處在三個(gè)并行交互(a、b 和c)的中間。用戶(hù)代理的客戶(hù)端連接器緩存無(wú)法滿(mǎn)足請(qǐng)求,因此它根據(jù)每個(gè)資源標(biāo)識(shí)符的屬性和客戶(hù)端連接器的配置,將每個(gè)請(qǐng)求路由到資源的來(lái)源。請(qǐng)求(a)被發(fā)送到一個(gè)本地代理,代理隨后訪問(wèn)一個(gè)通過(guò)DNS 查找發(fā)現(xiàn)的緩存網(wǎng)關(guān),該網(wǎng)關(guān)將這個(gè)請(qǐng)求轉(zhuǎn)發(fā)到一個(gè)能夠滿(mǎn)足該請(qǐng)求的來(lái)源服務(wù)器,服務(wù)器的內(nèi)部資源由一個(gè)封裝過(guò)的對(duì)象請(qǐng)求代理(object request broker)架構(gòu)來(lái)定義。請(qǐng)求(b)直接發(fā)送到一個(gè)來(lái)源服務(wù)器,它能夠通過(guò)自己的緩存來(lái)滿(mǎn)足這個(gè)請(qǐng)求。請(qǐng)求(c)被發(fā)送到一個(gè)代理,它能夠直接訪問(wèn)WAIS(一種與Web 架構(gòu)分離的信息服務(wù)),并將WAIS 的響應(yīng)翻譯為一種通用的連接器接口能夠識(shí)別的格式。每一個(gè)組件只知道與它們自己的客戶(hù)端或服務(wù)器連接器的交互;整個(gè)過(guò)程拓?fù)涫俏覀兊囊晥D的產(chǎn)物。
通過(guò)比較圖2 和圖3,讀者不難發(fā)現(xiàn)這兩張圖中的架構(gòu)是高度一致的。對(duì)于HTTP/1.1 協(xié)議為何要設(shè)計(jì)成這個(gè)樣子,讀者想必已經(jīng)有所領(lǐng)悟。
在論文的第六章中,F(xiàn)ielding 對(duì)于到2000 年為止在Web 基礎(chǔ)架構(gòu)協(xié)議的設(shè)計(jì)和開(kāi)發(fā)方面的一些經(jīng)驗(yàn)教訓(xùn)進(jìn)行了深入的分析。其中,“HTTP 不是RPC”、“HTTP 不是一種傳輸協(xié)議”兩部分值得讀者反復(fù)閱讀。時(shí)至13 年之后的今日,對(duì)于HTTP 協(xié)議的誤解仍然廣泛存在。
以上簡(jiǎn)要介紹了Fielding 博士論文中的內(nèi)容。為了幫助讀者仔細(xì)閱讀Fielding 的博士論文,筆者整理了一套Fielding 博士論文的導(dǎo)讀。
REST 詳解
REST 究竟是什么?因?yàn)?REST 的內(nèi)涵非常豐富,所以很難用一兩句話解釋清楚這個(gè)問(wèn)題。
首先,REST 是 Web 自身的架構(gòu)風(fēng)格。REST 也是 Web 之所以取得成功的技術(shù)架構(gòu)方面因素的總結(jié)。REST 是世界上最成功的分布式應(yīng)用架構(gòu)風(fēng)格(成功案例:Web,還不夠嗎?)。它是為 運(yùn)行在互聯(lián)網(wǎng)環(huán)境 的 分布式 超媒體系統(tǒng)量身定制的?;ヂ?lián)網(wǎng)環(huán)境與企業(yè)內(nèi)網(wǎng)環(huán)境有非常大的差別,最主要的差別是兩個(gè)方面:
- 可伸縮性需求無(wú)法控制:并發(fā)訪問(wèn)量可能會(huì)暴漲,也可能會(huì)暴跌。
- 安全性需求無(wú)法控制:無(wú)法控制客戶(hù)端發(fā)來(lái)的請(qǐng)求的格式,很可能會(huì)是惡意的請(qǐng)求。
而所謂的“超媒體系統(tǒng)”,即,使用了超文本的系統(tǒng)。可以把“超媒體”理解為超文本 + 媒體內(nèi)容。
REST 是 HTTP/1.1 協(xié)議等 Web 規(guī)范的設(shè)計(jì)指導(dǎo)原則,HTTP/1.1 協(xié)議正是為實(shí)現(xiàn) REST 風(fēng)格的架構(gòu)而設(shè)計(jì)的。新的 Web 規(guī)范,其設(shè)計(jì)必須符合 REST 的要求,否則整個(gè) Web 的體系架構(gòu)會(huì)因?yàn)橐雵?yán)重矛盾而崩潰。這句話不是危言聳聽(tīng),做個(gè)類(lèi)比,假如蘇州市政府同意在市區(qū)著名園林的附近大型土木,建造大量具有后現(xiàn)代風(fēng)格的摩天大樓,那么不久之后世界聞名的蘇州園林美景將不復(fù)存在。
上述這些關(guān)于“REST 是什么”的描述,可以總結(jié)為一句話:REST 是所有 Web 應(yīng)用都應(yīng)該遵守的架構(gòu)設(shè)計(jì)指導(dǎo)原則。當(dāng)然,REST 并不是法律,違反了 REST 的指導(dǎo)原則,仍然能夠?qū)崿F(xiàn)應(yīng)用的功能。但是違反了 REST 的指導(dǎo)原則,會(huì)付出很多代價(jià),特別是對(duì)于大流量的網(wǎng)站而言。
要深入理解 REST,需要理解 REST 的五個(gè)關(guān)鍵詞:
- 資源(Resource)
- 資源的表述(Representation)
- 狀態(tài)轉(zhuǎn)移(State Transfer)
- 統(tǒng)一接口(Uniform Interface)
- 超文本驅(qū)動(dòng)(Hypertext Driven)
什么是資源?
資源是一種看待服務(wù)器的方式,即,將服務(wù)器看作是由很多離散的資源組成。每個(gè)資源是服務(wù)器上一個(gè)可命名的抽象概念。因?yàn)橘Y源是一個(gè)抽象的概念,所以它不僅僅能代表服務(wù)器文件系統(tǒng)中的一個(gè)文件、數(shù)據(jù)庫(kù)中的一張表等等具體的東西,可以將資源設(shè)計(jì)的要多抽象有多抽象,只要想象力允許而且客戶(hù)端應(yīng)用開(kāi)發(fā)者能夠理解。與面向?qū)ο笤O(shè)計(jì)類(lèi)似,資源是以名詞為核心來(lái)組織的,首先關(guān)注的是名詞。一個(gè)資源可以由一個(gè)或多個(gè) URI 來(lái)標(biāo)識(shí)。URI 既是資源的名稱(chēng),也是資源在 Web 上的地址。對(duì)某個(gè)資源感興趣的客戶(hù)端應(yīng)用,可以通過(guò)資源的 URI 與其進(jìn)行交互。
什么是資源的表述?
資源的表述是一段對(duì)于資源在某個(gè)特定時(shí)刻的狀態(tài)的描述。可以在客戶(hù)端 - 服務(wù)器端之間轉(zhuǎn)移(交換)。資源的表述可以有多種格式,例如 HTML/XML/JSON/ 純文本 / 圖片 / 視頻 / 音頻等等。資源的表述格式可以通過(guò)協(xié)商機(jī)制來(lái)確定。請(qǐng)求 - 響應(yīng)方向的表述通常使用不同的格式。
什么是狀態(tài)轉(zhuǎn)移?
狀態(tài)轉(zhuǎn)移(state transfer)與狀態(tài)機(jī)中的狀態(tài)遷移(state transition)的含義是不同的。狀態(tài)轉(zhuǎn)移說(shuō)的是:在客戶(hù)端和服務(wù)器端之間轉(zhuǎn)移(transfer)代表資源狀態(tài)的表述。通過(guò)轉(zhuǎn)移和操作資源的表述,來(lái)間接實(shí)現(xiàn)操作資源的目的。
什么是統(tǒng)一接口?
REST 要求,必須通過(guò)統(tǒng)一的接口來(lái)對(duì)資源執(zhí)行各種操作。對(duì)于每個(gè)資源只能執(zhí)行一組有限的操作。以 HTTP/1.1 協(xié)議為例,HTTP/1.1 協(xié)議定義了一個(gè)操作資源的統(tǒng)一接口,主要包括以下內(nèi)容:
- 7 個(gè) HTTP 方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS
- HTTP 頭信息(可自定義)
- HTTP 響應(yīng)狀態(tài)代碼(可自定義)
- 一套標(biāo)準(zhǔn)的內(nèi)容協(xié)商機(jī)制
- 一套標(biāo)準(zhǔn)的緩存機(jī)制
- 一套標(biāo)準(zhǔn)的客戶(hù)端身份認(rèn)證機(jī)制
REST 還要求,對(duì)于資源執(zhí)行的操作,其操作語(yǔ)義必須由 HTTP 消息體之前的部分完全表達(dá),不能將操作語(yǔ)義封裝在 HTTP 消息體內(nèi)部。這樣做是為了提高交互的可見(jiàn)性,以便于通信鏈的中間組件實(shí)現(xiàn)緩存、安全審計(jì)等等功能。
什么是超文本驅(qū)動(dòng)?
“超文本驅(qū)動(dòng)”又名“將超媒體作為應(yīng)用狀態(tài)的引擎”(Hypermedia As The Engine Of Application State,來(lái)自 Fielding 博士論文中的一句話,縮寫(xiě)為 HATEOAS)。將 Web 應(yīng)用看作是一個(gè)由很多狀態(tài)(應(yīng)用狀態(tài))組成的有限狀態(tài)機(jī)。資源之間通過(guò)超鏈接相互關(guān)聯(lián),超鏈接既代表資源之間的關(guān)系,也代表可執(zhí)行的狀態(tài)遷移。在超媒體之中不僅僅包含數(shù)據(jù),還包含了狀態(tài)遷移的語(yǔ)義。以超媒體作為引擎,驅(qū)動(dòng) Web 應(yīng)用的狀態(tài)遷移。通過(guò)超媒體暴露出服務(wù)器所提供的資源,服務(wù)器提供了哪些資源是在運(yùn)行時(shí)通過(guò)解析超媒體發(fā)現(xiàn)的,而不是事先定義的。從面向服務(wù)的角度看,超媒體定義了服務(wù)器所提供服務(wù)的協(xié)議??蛻?hù)端應(yīng)該依賴(lài)的是超媒體的狀態(tài)遷移語(yǔ)義,而不應(yīng)該對(duì)于是否存在某個(gè) URI 或 URI 的某種特殊構(gòu)造方式作出假設(shè)。一切都有可能變化,只有超媒體的狀態(tài)遷移語(yǔ)義能夠長(zhǎng)期保持穩(wěn)定。
一旦讀者理解了上述 REST 的五個(gè)關(guān)鍵詞,就很容易理解 REST 風(fēng)格的架構(gòu)所具有的 6 個(gè)的主要特征:
- 面向資源(Resource Oriented)
- 可尋址(Addressability)
- 連通性(Connectedness)
- 無(wú)狀態(tài)(Statelessness)
- 統(tǒng)一接口(Uniform Interface)
- 超文本驅(qū)動(dòng)(Hypertext Driven)
這 6 個(gè)特征是 REST 架構(gòu)設(shè)計(jì)優(yōu)秀程度的判斷標(biāo)準(zhǔn)。其中,面向資源是 REST 最明顯的特征,即,REST 架構(gòu)設(shè)計(jì)是以資源抽象為核心展開(kāi)的。可尋址說(shuō)的是:每一個(gè)資源在 Web 之上都有自己的地址。連通性說(shuō)的是:應(yīng)該盡量避免設(shè)計(jì)孤立的資源,除了設(shè)計(jì)資源本身,還需要設(shè)計(jì)資源之間的關(guān)聯(lián)關(guān)系,并且通過(guò)超鏈接將資源關(guān)聯(lián)起來(lái)。無(wú)狀態(tài)、統(tǒng)一接口是 REST 的兩種架構(gòu)約束,超文本驅(qū)動(dòng)是 REST 的一個(gè)關(guān)鍵詞,在前面都已經(jīng)解釋過(guò),就不再贅述了。
從架構(gòu)風(fēng)格的抽象高度來(lái)看,常見(jiàn)的分布式應(yīng)用架構(gòu)風(fēng)格有三種:
- 分布式對(duì)象(Distributed Objects,簡(jiǎn)稱(chēng) DO)
架構(gòu)實(shí)例有 CORBA/RMI/EJB/DCOM/.NET Remoting 等等
- 遠(yuǎn)程過(guò)程調(diào)用(Remote Procedure Call,簡(jiǎn)稱(chēng) RPC)
架構(gòu)實(shí)例有 SOAP/XML-RPC/Hessian/Flash AMF/DWR 等等
- 表述性狀態(tài)轉(zhuǎn)移(Representational State Transfer,簡(jiǎn)稱(chēng) REST)
架構(gòu)實(shí)例有 HTTP/WebDAV
DO 和 RPC 這兩種架構(gòu)風(fēng)格在企業(yè)應(yīng)用中非常普遍,而 REST 則是 Web 應(yīng)用的架構(gòu)風(fēng)格,它們之間有非常大的差別。
REST 與 DO 的差別
- REST 支持抽象(即建模)的工具是資源,DO 支持抽象的工具是對(duì)象。在不同的編程語(yǔ)言中,對(duì)象的定義有很大差別,所以 DO 風(fēng)格的架構(gòu)通常都是與某種編程語(yǔ)言綁定的??缯Z(yǔ)言交互即使能實(shí)現(xiàn),實(shí)現(xiàn)起來(lái)也會(huì)非常復(fù)雜。而 REST 中的資源,則完全中立于開(kāi)發(fā)平臺(tái)和編程語(yǔ)言,可以使用任何編程語(yǔ)言來(lái)實(shí)現(xiàn)。
- DO 中沒(méi)有統(tǒng)一接口的概念。不同的 API,接口設(shè)計(jì)風(fēng)格可以完全不同。DO 也不支持操作語(yǔ)義對(duì)于中間組件的可見(jiàn)性。
- DO 中沒(méi)有使用超文本,響應(yīng)的內(nèi)容中只包含對(duì)象本身。REST 使用了超文本,可以實(shí)現(xiàn)更大粒度的交互,交互的效率比 DO 更高。
- REST 支持?jǐn)?shù)據(jù)流和管道,DO 不支持?jǐn)?shù)據(jù)流和管道。
- DO 風(fēng)格通常會(huì)帶來(lái)客戶(hù)端與服務(wù)器端的緊耦合。在三種架構(gòu)風(fēng)格之中,DO 風(fēng)格的耦合度是最大的,而 REST 的風(fēng)格耦合度是最小的。REST 松耦合的源泉來(lái)自于統(tǒng)一接口 + 超文本驅(qū)動(dòng)。
REST 與 RPC 的差別
- REST 支持抽象的工具是資源,RPC 支持抽象的工具是過(guò)程。REST 風(fēng)格的架構(gòu)建模是以名詞為核心的,RPC 風(fēng)格的架構(gòu)建模是以動(dòng)詞為核心的。簡(jiǎn)單類(lèi)比一下,REST 是面向?qū)ο缶幊?,RPC 則是面向過(guò)程編程。
- RPC 中沒(méi)有統(tǒng)一接口的概念。不同的 API,接口設(shè)計(jì)風(fēng)格可以完全不同。RPC 也不支持操作語(yǔ)義對(duì)于中間組件的可見(jiàn)性。
- RPC 中沒(méi)有使用超文本,響應(yīng)的內(nèi)容中只包含消息本身。REST 使用了超文本,可以實(shí)現(xiàn)更大粒度的交互,交互的效率比 RPC 更高。
- REST 支持?jǐn)?shù)據(jù)流和管道,RPC 不支持?jǐn)?shù)據(jù)流和管道。
- 因?yàn)槭褂昧似脚_(tái)中立的消息,RPC 風(fēng)格的耦合度比 DO 風(fēng)格要小一些,但是 RPC 風(fēng)格也常常會(huì)帶來(lái)客戶(hù)端與服務(wù)器端的緊耦合。支持統(tǒng)一接口 + 超文本驅(qū)動(dòng)的 REST 風(fēng)格,可以達(dá)到最小的耦合度。
比較了三種架構(gòu)風(fēng)格之間的差別之后,從面向?qū)嵱玫慕嵌葋?lái)看,REST 架構(gòu)風(fēng)格可以為 Web 開(kāi)發(fā)者帶來(lái)三方面的利益:
- 簡(jiǎn)單性
采用 REST 架構(gòu)風(fēng)格,對(duì)于開(kāi)發(fā)、測(cè)試、運(yùn)維人員來(lái)說(shuō),都會(huì)更簡(jiǎn)單??梢猿浞掷么罅?HTTP 服務(wù)器端和客戶(hù)端開(kāi)發(fā)庫(kù)、Web 功能測(cè)試 / 性能測(cè)試工具、HTTP 緩存、HTTP 代理服務(wù)器、防火墻。這些開(kāi)發(fā)庫(kù)和基礎(chǔ)設(shè)施早已成為了日常用品,不需要什么火箭科技(例如神奇昂貴的應(yīng)用服務(wù)器、中間件)就能解決大多數(shù)可伸縮性方面的問(wèn)題。
- 可伸縮性
充分利用好通信鏈各個(gè)位置的 HTTP 緩存組件,可以帶來(lái)更好的可伸縮性。其實(shí)很多時(shí)候,在 Web 前端做性能優(yōu)化,產(chǎn)生的效果不亞于僅僅在服務(wù)器端做性能優(yōu)化,但是 HTTP 協(xié)議層面的緩存常常被一些資深的架構(gòu)師完全忽略掉。
- 松耦合
統(tǒng)一接口 + 超文本驅(qū)動(dòng),帶來(lái)了最大限度的松耦合。允許服務(wù)器端和客戶(hù)端程序在很大范圍內(nèi),相對(duì)獨(dú)立地進(jìn)化。對(duì)于設(shè)計(jì)面向企業(yè)內(nèi)網(wǎng)的 API 來(lái)說(shuō),松耦合并不是一個(gè)很重要的設(shè)計(jì)關(guān)注點(diǎn)。但是對(duì)于設(shè)計(jì)面向互聯(lián)網(wǎng)的 API 來(lái)說(shuō),松耦合變成了一個(gè)必選項(xiàng),不僅在設(shè)計(jì)時(shí)應(yīng)該關(guān)注,而且應(yīng)該放在最優(yōu)先位置。
有的讀者可能會(huì)問(wèn):“你說(shuō)了這么多,REST 難道就沒(méi)有任何缺點(diǎn)了嗎?”當(dāng)然不是,正如 Fielding 在博士論文中闡述的那樣,評(píng)價(jià)一種軟件架構(gòu)的優(yōu)劣,不能脫離開(kāi)軟件的具體運(yùn)行環(huán)境。永遠(yuǎn)不存在適用于任何運(yùn)行環(huán)境的、包治百病的銀彈式架構(gòu)。筆者在前面強(qiáng)調(diào)過(guò) REST 是一種為運(yùn)行在互聯(lián)網(wǎng)環(huán)境中的 Web 應(yīng)用量身定制的架構(gòu)風(fēng)格。REST 在互聯(lián)網(wǎng)這個(gè)運(yùn)行環(huán)境之中已經(jīng)占據(jù)了統(tǒng)治地位,然而,在企業(yè)內(nèi)網(wǎng)運(yùn)行環(huán)境之中,REST 還會(huì)面臨 DO、RPC 的巨大挑戰(zhàn)。特別是一些對(duì)實(shí)時(shí)性要求很高的應(yīng)用,REST 的表現(xiàn)不如 DO 和 RPC。所以需要針對(duì)具體的運(yùn)行環(huán)境來(lái)具體問(wèn)題具體分析。但是,REST 可以帶來(lái)的上述三方面的利益即使在開(kāi)發(fā)企業(yè)應(yīng)用時(shí),仍然是非常有價(jià)值的。所以 REST 在企業(yè)應(yīng)用開(kāi)發(fā),特別是在 SOA 架構(gòu)的開(kāi)發(fā)中,已經(jīng)得到了越來(lái)越大的重視。本專(zhuān)欄將有一篇文章專(zhuān)門(mén)介紹 REST 在企業(yè)級(jí)應(yīng)用中與 SOA 的結(jié)合。
到了這里,“REST 究竟是什么”這個(gè)問(wèn)題筆者就解答完了。本文開(kāi)頭那些說(shuō)法是否正確,筆者還是笑而不語(yǔ),讀者此時(shí)應(yīng)該已經(jīng)有了自己的判斷。在接下來(lái)的 REST 系列文章中,我將會(huì)為讀者澄清一些關(guān)于 HTTP 協(xié)議和 REST 的常見(jiàn)誤解。
參考資料:
以上就是本真的REST架構(gòu)風(fēng)格理解的詳細(xì)內(nèi)容,更多關(guān)于REST架構(gòu)風(fēng)格的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
淺談Java編程之if-else的優(yōu)化技巧總結(jié)
說(shuō)實(shí)話,其實(shí)我很討厭在代碼里大量使用if-else,一是因?yàn)樵擃?lèi)代碼執(zhí)行方式屬于面向過(guò)程的,二嘛,則是會(huì)顯得代碼過(guò)于冗余.這篇筆記,主要記錄一些自己在工作實(shí)踐當(dāng)中針對(duì)if-else的優(yōu)化心得,將會(huì)不定期地長(zhǎng)期更新,需要的朋友可以參考下2021-06-06
Springboot集成RabbitMQ并驗(yàn)證五種消息模型
RabbitMQ 提供了5種常用消息模型,本文主要介紹了Springboot集成RabbitMQ并驗(yàn)證五種消息模型,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
RocketMq 消息重試機(jī)制及死信隊(duì)列詳解
這篇文章主要為大家介紹了RocketMq 消息重試機(jī)制及死信隊(duì)列詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
SpringBoot之通過(guò)BeanPostProcessor動(dòng)態(tài)注入ID生成器案例詳解
這篇文章主要介紹了SpringBoot之通過(guò)BeanPostProcessor動(dòng)態(tài)注入ID生成器案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09
SpringBoot框架集成ElasticSearch實(shí)現(xiàn)過(guò)程示例詳解
這篇文章主要為大家介紹了SpringBoot如何集成ElasticSearch的實(shí)現(xiàn)過(guò)程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11
SpringBoot自定義注解使用讀寫(xiě)分離Mysql數(shù)據(jù)庫(kù)的實(shí)例教程
這篇文章主要給大家介紹了關(guān)于SpringBoot自定義注解使用讀寫(xiě)分離Mysql數(shù)據(jù)庫(kù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
java 方法重寫(xiě)與權(quán)限修飾符以及多態(tài)和抽象類(lèi)詳解概念和用法
重寫(xiě)是子類(lèi)對(duì)父類(lèi)的允許訪問(wèn)的方法的實(shí)現(xiàn)過(guò)程進(jìn)行重新編寫(xiě), 返回值和形參都不能改變。即外殼不變,核心重寫(xiě),權(quán)限修飾符用于控制被修飾變量、方法、類(lèi)的可見(jiàn)范圍,說(shuō)明了面向?qū)ο蟮姆庋b性,所以我們要適用他們盡可能的讓權(quán)限降到最低,從而安全性提高2021-10-10

