官术网_书友最值得收藏!

2.2.1 理解REST

個人會有好惡偏愛,但計算機科學是務實的,有了RPC,還會提出REST,有了面向過程編程之后還會產生面向資源編程,并引起廣泛的關注、使用和討論,說明后者一定是有一些前者沒有的閃光點,或者解決、避免了一些前者的缺陷。我們不妨先去理解REST為什么會出現,再來討論評價它。

REST源于Roy Thomas Fielding在2000年發表的博士論文“Architectural Styles and the Design of Network-based Software Architectures”[1],此文的確是REST的源頭,但我們不應該忽略Fielding的身份和他此前的工作背景,這些信息對理解REST的設計思想至關重要。

首先,Fielding是一名很優秀的軟件工程師,他是Apache服務器的核心開發者,后來成為著名的Apache軟件基金會的聯合創始人;同時,Fielding也是HTTP 1.0協議(1996年發布)的專家組成員,后來還晉升為HTTP 1.1協議(1999年發布)的負責人。HTTP 1.1協議設計得極為成功,以至于在發布之后長達十年的時間里,都沒有收到多少修訂的意見。用來指導HTTP 1.1協議設計的理論和思想,最初是以備忘錄的形式供專家組成員之間交流,除了IETF、W3C的專家外,并沒有在外界廣泛流傳。

從時間上看,對HTTP 1.1協議的設計工作貫穿了Fielding的整個博士研究生涯,當起草HTTP 1.1協議的工作完成后,Fielding回到了加州大學歐文分校繼續攻讀自己的博士學位。第二年,他更為系統、嚴謹地闡述了這套理論框架,同時以這套理論框架導出了一種新的編程思想,并為這種程序設計風格取了一個很多人難以理解,但是今天已經廣為人知的名字——REST(Representational State Transfer,表征狀態轉移)。

哪怕對編程和網絡都很熟悉的同學,也不太可能直接從名字弄明白什么叫“表征”、什么東西的“狀態”、從哪“轉移”到哪。盡管在論文中確有論述這些概念,但寫得相當晦澀[2],所以筆者比較推薦先理解什么是HTTP,再配合一些實際例子來對兩者進行類比,以更清楚地了解REST,你會發現REST實際上是“HTT”(Hypertext Transfer)的進一步抽象,兩者的關系就如同接口與實現類的關系一般。

HTTP中使用的“超文本”(Hypertext)一詞是美國社會學家Theodor Holm Nelson在1967年于“Brief Words on the Hypertext”一文里提出的,下面引用的是他本人在1992年修正后的定義:

額外知識

現在,“超文本”一詞已被普遍接受,它指的是能夠進行分支判斷和差異響應的文本,相應地,“超媒體”一詞指的是能夠進行分支判斷和差異響應的圖像、電影和聲音(也包括文本)的復合體。

——Theodor Holm Nelson,Literary Machines,1992

以上定義描述的“超文本(或超媒體)”是一種“能夠對操作進行判斷和響應的文本(或聲音、圖像等)”,這個概念在20世紀60年代提出時應該還屬于科幻的范疇,但是今天大眾已經完全接受了它,互聯網中一段文字可以點擊、可以觸發腳本執行、可以調用服務端已毫不稀奇。下面我們繼續嘗試從“超文本”或者“超媒體”的含義來理解什么是“表征”以及REST中的其他關鍵概念,這里使用一個具體事例將其描述如下。

·資源(Resource):譬如你現在正在閱讀一篇名為《REST設計風格》的文章,這篇文章的內容本身(你可以將其理解為蘊含的信息、數據)稱之為“資源”。無論你是通過閱讀購買的圖書、瀏覽器上的網頁還是打印出來的文稿,無論是在電腦屏幕上閱讀還是在手機上閱讀,盡管呈現的樣子各不相同,但其中的信息是不變的,你所閱讀的仍是同一份“資源”。

·表征(Representation):當你通過瀏覽器閱讀此文章時,瀏覽器會向服務端發出“我需要這個資源的HTML格式”的請求,服務端向瀏覽器返回的這個HTML就被稱為“表征”,你也可以通過其他方式拿到本文的PDF、Markdown、RSS等其他形式的版本,它們同樣是一個資源的多種表征。可見“表征”是指信息與用戶交互時的表示形式,這與我們軟件分層架構中常說的“表示層”(Presentation Layer)的語義其實是一致的。

·狀態(State):當你讀完了這篇文章,想看后面是什么內容時,你向服務端發出“給我下一篇文章”的請求。但是“下一篇”是個相對概念,必須依賴“當前你正在閱讀的文章是哪一篇”才能正確回應,這類在特定語境中才能產生的上下文信息被稱為“狀態”。我們所說的有狀態(Stateful)抑或是無狀態(Stateless),都是只相對于服務端來說的,服務端要完成“取下一篇”的請求,要么自己記住用戶的狀態,如這個用戶現在閱讀的是哪一篇文章,這稱為有狀態;要么由客戶端來記住狀態,在請求的時候明確告訴服務端,如我正在閱讀某某文章,現在要讀它的下一篇,這稱為無狀態。

·轉移(Transfer):無論狀態是由服務端還是由客戶端來提供,“取下一篇文章”這個行為邏輯只能由服務端來提供,因為只有服務端擁有該資源及其表征形式。服務端通過某種方式,把“用戶當前閱讀的文章”轉變成“下一篇文章”,這就被稱為“表征狀態轉移”。

通過“閱讀文章”這個例子,相信你應該能夠理解“表征狀態轉移”的含義了。借著這個故事的上下文狀態,筆者再繼續介紹幾個現在不涉及但稍后要用到的概念。

·統一接口(Uniform Interface):上面說的服務端“通過某種方式”讓表征狀態轉移,那具體是什么方式呢?如果你真的是用瀏覽器閱讀本文電子版的話,請把本文滾動到結尾處,右下角有下一篇文章的URI超鏈接地址,這是服務端渲染這篇文章時就預置好的,點擊它讓頁面跳轉到下一篇,就是所謂“某種方式”的其中一種方式。任何人都不會對點擊超鏈接網頁出現跳轉感到奇怪,但你細想一下,URI的含義是統一資源標識符,是一個名詞,如何能表達出“轉移”動作的含義呢?答案是HTTP協議中已經提前約定好了一套“統一接口”,它包括GET、HEAD、POST、PUT、DELETE、TRACE、OPTIONS七種基本操作,任何一個支持HTTP協議的服務器都會遵守這套規定,對特定的URI采取這些操作,服務器就會觸發相應的表征狀態轉移。

·超文本驅動(Hypertext Driven):盡管表征狀態轉移是由瀏覽器主動向服務器發出請求所引發的,該請求導致了“在瀏覽器屏幕上顯示出了下一篇文章的內容”的結果。但是,我們都清楚這不可能真的是瀏覽器的主動意圖,瀏覽器是根據用戶輸入的URI地址來找到網站首頁,讀取服務器給予的首頁超文本內容后,瀏覽器再通過超文本內部的鏈接來導航到這篇文章,閱讀結束時,也是通過超文本內部的鏈接再導航到下一篇。瀏覽器作為所有網站的通用的客戶端,任何網站的導航(狀態轉移)行為都不可能是預置于瀏覽器代碼之中,而是由服務器發出的請求響應信息(超文本)來驅動的。這點與其他帶有客戶端的軟件有十分本質的區別,在那些軟件中,業務邏輯往往是預置于程序代碼之中的,有專門的頁面控制器(無論在服務端還是在客戶端中)來驅動頁面的狀態轉移。

·自描述消息(Self-Descriptive Message):由于資源的表征可能存在多種不同形態,在消息中應當有明確的信息來告知客戶端該消息的類型以及應如何處理這條消息。一種被廣泛采用的自描述方法是在名為“Content-Type”的HTTP Header中標識出互聯網媒體類型(MIME type),譬如“Content-Type:application/json;charset=utf-8”說明該資源會以JSON的格式來返回,請使用UTF-8字符集進行處理。

除了以上列出的這些概念外,在理解REST的過程中,還有一個常見的誤區值得注意:Fielding提出REST時所談論的范圍是“架構風格與網絡的軟件架構設計”(Architectural Styles and Design of Network-based Software Architecture),而不是現在被人們所狹義理解的一種“遠程服務設計風格”,這兩者的范圍差別就好比本書所談論的話題“軟件架構”與本章談論話題“訪問遠程服務”的關系那樣,前者是后者的一個很大的超集,盡管基于本節的主題和多數人的關注點考慮,我們確實會以“遠程服務設計風格”作為討論的重點,但至少應該說清楚它們范圍上的差別。

[1] 下載地址:https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm。

[2] 不想讀英文的同學從此處獲得中文翻譯版本:https://www.infoq.cn/article/2007/07/dlee-fielding-rest/。

主站蜘蛛池模板: 株洲县| 玉田县| 余江县| 丘北县| 白河县| 额敏县| 体育| 广平县| 遵义县| 邓州市| 仪征市| 嘉义县| 广东省| 香格里拉县| 精河县| 华容县| 集安市| 兴义市| 扬中市| 屏山县| 抚顺市| 佛山市| 准格尔旗| 西城区| 宜阳县| 门头沟区| 永定县| 九江县| 增城市| 正阳县| 正安县| 峨山| 辛集市| 旺苍县| 六盘水市| 徐水县| 万荣县| 磐石市| 翁牛特旗| 康马县| 平果县|