你真的了解REST嗎整袁?

背景

過五關(guān),斬六將佑吝,一路殺到了最后一面坐昙,很高興加入了素有“武林正宗少林派”的阿里,而阿里的技術(shù)又充滿著黑科技感芋忿。不過最近我接手了一個老系統(tǒng)時炸客,發(fā)現(xiàn)其中對于REST的應(yīng)用可能有些誤區(qū),于是才想寫一篇關(guān)于REST的介紹戈钢,以便分享給團隊中其他的同學(xué)痹仙。

本篇文章主要包括以下幾個方面:

  1. REST的概念是什么
  2. 我們?yōu)槭裁葱枰猂EST
  3. 前端渲染和后端渲染的優(yōu)勢是什么
  4. 什么樣的REST才是"正宗"的

一、REST的概念是什么

  • 維基百科
    表現(xiàn)層狀態(tài)轉(zhuǎn)換(REST殉了,英文:Representational State Transfer)是Roy Thomas Fielding博士于2000年在他的博士論文中提出來的一種萬維網(wǎng)軟件架構(gòu)風(fēng)格开仰,目的是便于不同軟件/程序在網(wǎng)絡(luò)(例如互聯(lián)網(wǎng))中互相傳遞信息。

論文地址:Architectural Styles and the Design of Network-based Software Architectures
REST章節(jié):Fielding Dissertation: CHAPTER 5: Representational State Transfer (REST)

  • 知乎
    [資源]表現(xiàn)層狀態(tài)轉(zhuǎn)換(REST,英文:[Resource] Representational State Transfer)众弓,通俗翻譯為:資源在網(wǎng)絡(luò)中以某種表現(xiàn)形式進行狀態(tài)轉(zhuǎn)移恩溅。

Resource:資源,即數(shù)據(jù)(網(wǎng)絡(luò)的核心)谓娃,比如 goods脚乡,fruits等;
Representational:某種表現(xiàn)形式滨达,比如用JSON奶稠,XML,JPEG等捡遍;
State Transfer:狀態(tài)變化窒典,通過HTTP動詞實現(xiàn)。

二稽莉、我們?yōu)槭裁葱枰猂EST

在前面介紹了REST的概念瀑志,不過對于初次接觸REST的同學(xué)來說,可能會覺得晦澀難懂污秆,因為只有幾個新的名詞概念解釋而已劈猪,對于我們來說它又有什么用呢?

在介紹REST的作用之前良拼,我們先了解一下在REST沒有出現(xiàn)之前的Web開發(fā)是什么樣的?

早期的Web 項目一般是在服務(wù)器端進行渲染战得,服務(wù)器進程從數(shù)據(jù)庫獲取數(shù)據(jù)后,然后利用后端模板引擎(比如Velocity庸推、Freemaker 等)或者直接在HTML 模板中嵌入后端語言(比如JSP常侦、PHP),將數(shù)據(jù)加載進來生成HTML贬媒,然后通過網(wǎng)絡(luò)傳輸?shù)接脩舻臑g覽器中聋亡,最后被瀏覽器解析成可見的頁面。具體的過程如下圖所示:

服務(wù)端渲染

此時大多數(shù)服務(wù)器架構(gòu)都是這種 MVC 模式际乘,前端只需要一次HTTP請求就可以返回整個頁面內(nèi)容坡倔,加載速度可能會稍微快些。但是它的缺點也非常明顯脖含,前端寫完靜態(tài)頁面罪塔,要讓后臺去套模板,每次前端稍有改動养葵,后臺對應(yīng)的模板頁面同時也需要改動征堪,而且頁面中可能會包含大量復(fù)雜的 JS代碼,比如美工同學(xué)(當(dāng)時的前端)需要通過JS寫界面的交互关拒,而后端同學(xué)又需要通過JS實現(xiàn)數(shù)據(jù)的渲染佃蚜,非常地麻煩庸娱。

當(dāng)然事情麻煩歸麻煩,但還不至于引發(fā)新的技術(shù)革命爽锥,而真正推動REST發(fā)展的是移動互聯(lián)網(wǎng)的出現(xiàn)涌韩。由于多終端設(shè)備的兼容性需求,從前的服務(wù)端渲染已經(jīng)很難滿足要求了氯夷。服務(wù)端不可能針對每一個Client渲染一套界面臣樱,如果服務(wù)端只提供需要的數(shù)據(jù),而具體界面的渲染完全交給具體的Client來完成腮考,因此催生了REST的發(fā)展和普及雇毫。

RESTful可以通過一套統(tǒng)一的接口為 Web、iOS和Android提供服務(wù)踩蔚,另外對于很多平臺來說(比如像Facebook棚放,Twiter、微博馅闽、微信等開放平臺)飘蚯,它們不需要有顯式的前端,只需要一套提供服務(wù)的接口福也,于是RESTful便是它們最好的選擇局骤。

REST API

三、前端渲染和后端渲染的優(yōu)勢是什么

隨著前端渲染引擎的發(fā)展暴凑,新興的Angular峦甩,React,Vue等的出現(xiàn)现喳,真正地實現(xiàn)了前后端分離解耦:前端專注于UI凯傲,負(fù)責(zé)View和Controller層,后端專注于業(yè)務(wù)/數(shù)據(jù)處理嗦篱,負(fù)責(zé)Model層冰单,兩端通過設(shè)計好的REST API進行交互。

圖片來自阿里玉伯的文章

參考文章
https://github.com/lifesinger/blog/issues/184
https://wenku.baidu.com/view/4c7b010c17fc700abb68a98271fe910ef12dae01

雖然現(xiàn)在前后端分離早已不是什么新鮮話題默色,不過前后端分離到底有什么樣的優(yōu)勢呢球凰?我們可以對比一下各自的優(yōu)點。

后端渲染的優(yōu)點:

  • 1腿宰、對搜索引擎友好,這樣做有利于 SEO缘厢。
  • 2吃度、加載時間短,后端渲染加載完成后就直接顯示HTML贴硫,但前端渲染在加載完成后還需要有段js 渲染的時間椿每。

前端渲染的優(yōu)點:

  • 1伊者、讓前后端的職責(zé)更清晰,分工更合理高效间护。前后端業(yè)務(wù)分離亦渗,后端只需要提供數(shù)據(jù)接口,前端在開發(fā)時也不需要部署對應(yīng)的后端環(huán)境汁尺,可以通過Mock數(shù)據(jù)進行并發(fā)開發(fā)法精。
  • 2、計算量轉(zhuǎn)移痴突,原本由服務(wù)器執(zhí)行的渲染任務(wù)轉(zhuǎn)移給了客戶端搂蜓,這在大量用戶訪問的時候大大減輕后端的壓力。讓后端專注做后端應(yīng)該做的事情辽装,性能將大大提高帮碰,因為服務(wù)器做的事情確實減小了。

前后端分離+Node層優(yōu)點:

  • 通過 Node拾积,Web Server 層也是 JavaScript 代碼殉挽,這意味著部分代碼可前后復(fù)用,需要 SEO 的場景可以在服務(wù)端同步渲染拓巧,由于異步請求太多導(dǎo)致的性能問題也可以通過服務(wù)端來緩解斯碌,結(jié)合了前兩種模式的優(yōu)點。

言歸正傳玲销,前面介紹了什么是REST输拇,也介紹了它的優(yōu)勢,接下來詳細(xì)介紹REST的具體內(nèi)容贤斜。

四策吠、什么樣的REST才是"正宗"的

無狀態(tài)原則

遵循REST范式的系統(tǒng)是無狀態(tài)的,這意味著服務(wù)器不需要知道客戶端處于什么狀態(tài)瘩绒,反之亦然猴抹。這樣,即使沒有看到以前的消息锁荔,服務(wù)器和客戶端都可以理解收到的任何消息蟀给。這種的無狀態(tài)約束是通過使用資源來實現(xiàn)的。資源是Web中的特定名詞——它描述了任何你可能需要存儲或發(fā)送到其他服務(wù)的對象或文檔阳堕。

無狀態(tài)原則是RESTful架構(gòu)設(shè)計中一個非常重要的原則跋理,無狀態(tài)是相對于有狀態(tài)而言的,我們首先看一下什么是有狀態(tài)的恬总。

Web服務(wù)的狀態(tài)一般指的是請求的狀態(tài)前普,是客戶端和服務(wù)端進行交互操作時所留下來的公共信息(比如,用戶的信息等)壹堰。這些信息可以被指定在不同的作用域中(如request拭卿、session骡湖、application等),通常由服務(wù)端來保存這些信息峻厚。

而無狀態(tài)的Web服務(wù)是指每一個Web請求都是獨立的响蕴,服務(wù)端沒有保存任何客戶端的狀態(tài)信息,所以客戶端發(fā)送的請求必須包含有能夠讓服務(wù)端理解請求的全部信息惠桃。

另外由于REST系統(tǒng)通過資源上的標(biāo)準(zhǔn)操作進行交互浦夷,因此它們不依賴于接口的實現(xiàn),使得RESTful應(yīng)用程序具有可靠性刽射、快速性和可擴展性军拟。

前后端通信機制

1、請求方式
REST要求客戶端向服務(wù)端發(fā)出請求以獲得或修改服務(wù)器上的數(shù)據(jù)誓禁。請求通常由以下部分組成:

  • 一個HTTP動詞懈息,它定義了要執(zhí)行的操作類型
  • 一個頭部,它允許客戶端傳遞關(guān)于請求的信息
  • 一條資源的路徑
  • 一個包含數(shù)據(jù)的可選消息主體

(1)對于HTTP動詞

在REST系統(tǒng)中我們使用4個基本HTTP動詞來與資源進行交互:

  • GET - 檢索特定資源(通過id)或資源集合
  • POST - 創(chuàng)建一個新資源
  • PUT - 更新特定資源(通過ID)
  • DELETE - 按ID刪除特定資源

(2)對于請求頭部

客戶端向服務(wù)端發(fā)送它能夠接收的內(nèi)容的類型摹恰,而該類型是通過一個叫Accept的字段發(fā)送的辫继。通過這種方式可以確保服務(wù)端不會發(fā)送客戶端無法理解或者無法處理的數(shù)據(jù)。

用于指定Accept字段的類型為MIME類型俗慈,它是由一個type和一個subtype通過斜線(/)分隔組成的姑宽。你可以在MDN Web文檔中查看更多關(guān)于MIME類型的介紹。

例如闺阱,包含HTML的文本文件類型指定為text/html炮车,而包含CSS的文本文件需要指定為text/css,一般的文本文件將被指定為text/plain(如果不指定酣溃,則默認(rèn)值為text/plain)瘦穆。假如客戶期待的類型為text/css,而接收到的類型text/plain赊豌,那么客戶端將無法識別它扛或。以下列舉了其他的type和subtype:

  • image — image/png, image/jpeg, image/gif
  • audio — audio/wav, image/mpeg
  • video — video/mp4, video/ogg
  • application — application/json, application/pdf, application/xml, application/octet-stream

(3)對于資源路徑
在RESTful API中,每一個請求的動作都必須作用于一個資源路徑上碘饼,所以資源路徑的設(shè)計就是為了讓客戶端能夠理解它所進行的操作是什么熙兔。

通常情況下,路徑的第一部分應(yīng)該是資源的復(fù)數(shù)形式艾恼。RESTful中這種路徑嵌套方式簡單易讀住涉,也更容易理解。示例如下:

https://www.alipay.com/customers/22/orders/11

該RESTful API指向的路徑非常清晰钠绍,因為它具有層次性和自描述性秆吵。該示例中,我們查詢了id號為22這位顧客的一筆訂單五慈,并且該訂單的id號為11纳寂。

路徑必須包含它所需要的能夠準(zhǔn)確定位它所代表的資源位置的信息。但是泻拦,如果引用的資源為列表或集合時毙芜,就不需要再向POST請求添加id這樣的唯一標(biāo)識了,因為在服務(wù)端將為該新對象生成一個唯一標(biāo)識id的争拐。例如向顧客集合中新增一位顧客:

POST https://www.alipay.com/customers

如果我們試圖訪問單個資源腋粥,則需要在路徑后面添加一個id,例如通過指定的id來查詢一位顧客:

GET https://www.alipay.com/customers/:id 

或者架曹,通過指定的id來刪除一位顧客:

DELETE https://www.alipay.com/customers/:id

2隘冲、接收內(nèi)容
在服務(wù)器向客戶端發(fā)送數(shù)據(jù)有效載荷的情況下,服務(wù)器必須content-type在響應(yīng)的頭部包含一個绑雄。這個content-type頭域告訴客戶端它在響應(yīng)主體中發(fā)送的數(shù)據(jù)的類型展辞。這些內(nèi)容類型是MIME類型,就像它們在accept請求頭的字段中一樣万牺。該content-type服務(wù)器在響應(yīng)發(fā)送回應(yīng)的客戶機中指定的選項之一accept的請求的字段罗珍。

例如,當(dāng)客戶端使用此GET請求訪問具有資源id23的articles資源時:

GET /articles/23 HTTP/1.1
Accept: text/html, application/xhtml

服務(wù)器可能會使用響應(yīng)頭發(fā)回內(nèi)容:

HTTP/1.1 200 (OK)
Content-Type: text/html

這將意味著所請求的內(nèi)容被返回的響應(yīng)體用content-type的text/html脚粟,該客戶表示覆旱,將能夠接受。

3核无、返回狀態(tài)
在服務(wù)器向客戶端發(fā)送數(shù)據(jù)有效載荷的情況下扣唱,服務(wù)器必須content-type在響應(yīng)的頭部包含一個。這個content-type頭域告訴客戶端它在響應(yīng)主體中發(fā)送的數(shù)據(jù)的類型团南。這些內(nèi)容類型是MIME類型噪沙,就像它們在accept請求頭的字段中一樣。該content-type服務(wù)器在響應(yīng)發(fā)送回應(yīng)的客戶機中指定的選項之一accept的請求的字段已慢。

例如曲聂,當(dāng)客戶端使用此GET請求訪問具有資源id23的articles資源時:

GET /articles/23 HTTP/1.1
Accept: text/html, application/xhtml

服務(wù)器可能會使用響應(yīng)頭發(fā)回內(nèi)容:

HTTP/1.1 200 (OK)
Content-Type: text/html

來自服務(wù)器的響應(yīng)包含狀態(tài)代碼,以提醒客戶有關(guān)操作成功的信息佑惠。作為開發(fā)人員朋腋,您不需要知道每個狀態(tài)代碼(其中有很多),但您應(yīng)該知道最常見的狀態(tài)代碼以及它們的使用方式:

狀態(tài)碼 含義
200 (OK) 這是成功HTTP請求的標(biāo)準(zhǔn)響應(yīng)膜楷。
201 (CREATED) 這是導(dǎo)致成功創(chuàng)建項目的HTTP請求的標(biāo)準(zhǔn)響應(yīng)旭咽。
204 (NO CONTENT) 這是成功HTTP請求的標(biāo)準(zhǔn)響應(yīng),響應(yīng)正文中沒有任何內(nèi)容被返回赌厅。
400 (BAD REQUEST) 由于請求語法錯誤穷绵,大小過大或其他客戶端錯誤,無法處理該請求特愿。
403 (FORBIDDEN) 客戶端沒有權(quán)限訪問此資源仲墨。
404 (NOT FOUND) 此時無法找到該資源勾缭。它可能已被刪除,或尚不存在目养。
500 (INTERNAL SERVER ERROR) 如果沒有更多可用的特定信息俩由,則通用答案意外失敗。

對于每個HTTP動詞癌蚁,服務(wù)器在成功時應(yīng)返回預(yù)期的狀態(tài)代碼:

  • GET - 返回200(OK)幻梯。
  • POST - 返回201(創(chuàng)建)。
  • PUT - 返回200(OK)努释。
  • DELETE - 返回204(無內(nèi)容)碘梢。如果操作失敗,則返回可能對應(yīng)于遇到的問題的最具體的狀態(tài)碼伐蒂。

4煞躬、CRUD示例說明
現(xiàn)在我們需要設(shè)計一個班級管理的系統(tǒng),其中需要有班級信息和班級的學(xué)生信息饿自。那我們該怎么為它設(shè)計REST接口呢汰翠?可以按照以下幾點思考:

  1. 使用什么樣的請求方式?
  2. 服務(wù)端返回是什么樣的昭雌?
  3. 通過什么樣的content-type傳輸內(nèi)容复唤?
  • 首先定義班級和學(xué)生的數(shù)據(jù)模型如下。
{
  “class”: {
    "id": <Integer>,
    “name”: <String>,
    “num”:  <Integer>
  }
}
{
  “ student”: {
    "id": <Integer>,
    “name”: <String>,
    “age”:  <Integer>
  }
}
  • 接口請求/響應(yīng)的定義烛卧。

GET請求:

接口 請求方式 傳輸格式(Content-type) 返回狀態(tài)
/classes GET application/json 200 (OK)
/classes/:id GET application/json 200 (OK)
/classes/:id/students GET application/json 200 (OK)
/classes/:id/students/:id GET application/json 200 (OK)

POST請求:

接口 請求方式 傳輸格式(Content-type) 返回狀態(tài)
/classes POST application/json 201 (CREATED)
/classes/:id/students POST application/json 201 (CREATED)

PUT請求:

接口 請求方式 傳輸格式(Content-type) 返回狀態(tài)
/classes/:id PUT application/json 200 (OK)
/classes/:id/students/:id PUT application/json 200 (OK)

DELETE請求:

接口 請求方式 傳輸格式(Content-type) 返回狀態(tài)
/classes/:id DELETE application/json 204 (NO CONTENT)
/classes/:id/students/:id DELETE application/json 204 (NO CONTENT)

小結(jié)

本文介紹了REST的相關(guān)概念佛纫,同時介紹了我們?yōu)槭裁葱枰猂EST,分析了前端渲染和后端渲染的優(yōu)勢是什么总放,然后再介紹了什么樣的REST才是"正宗"的呈宇,最后通過一個示例完整的演示了CRUD的操作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末局雄,一起剝皮案震驚了整個濱河市甥啄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炬搭,老刑警劉巖蜈漓,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宫盔,居然都是意外死亡融虽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門灼芭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來有额,“玉大人,你說我怎么就攤上這事∥∮樱” “怎么了茴迁?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長句狼。 經(jīng)常有香客問我笋熬,道長,這世上最難降的妖魔是什么腻菇? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮昔馋,結(jié)果婚禮上筹吐,老公的妹妹穿的比我還像新娘。我一直安慰自己秘遏,他們只是感情好丘薛,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邦危,像睡著了一般洋侨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上倦蚪,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天希坚,我揣著相機與錄音,去河邊找鬼陵且。 笑死裁僧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的慕购。 我是一名探鬼主播聊疲,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼沪悲!你這毒婦竟也來了获洲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤殿如,失蹤者是張志新(化名)和其女友劉穎贡珊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體握截,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡胀溺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年可都,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡速址,死狀恐怖潘拱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤逢防,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站蒲讯,受9級特大地震影響忘朝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜判帮,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一局嘁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晦墙,春花似錦悦昵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抗楔,卻和暖如春棋凳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背连躏。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工剩岳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人反粥。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓卢肃,卻偏偏與公主長得像,于是被迫代替她去往敵國和親才顿。 傳聞我的和親對象是個殘疾皇子莫湘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

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

  • 前端開發(fā)者丨h(huán)ttp請求 https:www.rokub.com 前言見解有限, 如有描述不當(dāng)之處郑气, 請幫忙指出幅垮,...
    麋鹿_720a閱讀 10,909評論 11 31
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)尾组,斷路器忙芒,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,071評論 25 707
  • 感恩錢寶寶的魔力,開通了流量讳侨,及時掌握家長群里的動態(tài)呵萨,感恩學(xué)校網(wǎng)絡(luò)故障,心里不再惦念手機里未刷的圈跨跨,未更的博潮峦。...
    娜些事閱讀 386評論 0 0
  • CocoaPods : 本地安裝與管理 關(guān)于cocoapads 的安裝與管理第三方管理相比都比較了解囱皿,詳細(xì)請看相關(guān)...
    令狐靈犀閱讀 445評論 0 0