天天看點

資深技術專家楊彪:你真的了解REST嗎?小結

 ●  REST的概念是什麼

 ●  我們為什麼需要REST

 ●  前端渲染和後端渲染的優勢是什麼

 ●  什麼樣的REST才是"正宗"的

REST的概念是什麼

 ●  維基百科

表現層狀态轉換(REST,英文:Representational State Transfer)是Roy Thomas Fielding博士于2000年在他的博士論文中提出來的一種網際網路軟體架構風格,目的是便于不同軟體/程式在網絡(例如網際網路)中互相傳遞資訊。

論文位址:Architectural Styles and the Design of Network-based Software Architectures

REST章節:Fielding Dissertation: CHAPTER 5: Representational State Transfer (REST)

 ●  知乎

[資源]表現層狀态轉換(REST,英文:[Resource] Representational State Transfer),通俗翻譯為:資源在網絡中以某種表現形式進行狀态轉移。

Resource:資源,即資料(網絡的核心),比如 goods,fruits等;

Representational:某種表現形式,比如用JSON,XML,JPEG等;

State Transfer:狀态變化,通過HTTP動詞實作。

我們為什麼需要REST

在前面介紹了REST的概念,不過對于初次接觸REST的同學來說,可能會覺得晦澀難懂,因為隻有幾個新的名詞概念解釋而已,對于我們來說它又有什麼用呢?

在介紹REST的作用之前,我們先了解一下在REST沒有出現之前的Web開發是什麼樣的?

早期的Web 項目一般是在伺服器端進行渲染,伺服器程序從資料庫擷取資料後,然後利用後端模闆引擎(比如Velocity、Freemaker 等)或者直接在HTML 模闆中嵌入後端語言(比如JSP、PHP),将資料加載進來生成HTML,然後通過網絡傳輸到使用者的浏覽器中,最後被浏覽器解析成可見的頁面。具體的過程如下圖所示:

資深技術專家楊彪:你真的了解REST嗎?小結

服務端渲染

此時大多數伺服器架構都是這種 MVC 模式,前端隻需要一次HTTP請求就可以傳回整個頁面内容,加載速度可能會稍微快些。但是它的缺點也非常明顯,前端寫完靜态頁面,要讓背景去套模闆,每次前端稍有改動,背景對應的模闆頁面同時也需要改動,而且頁面中可能會包含大量複雜的 JS代碼,比如美工同學(當時的前端)需要通過JS寫界面的互動,而後端同學又需要通過JS實作資料的渲染,非常地麻煩。

當然事情麻煩歸麻煩,但還不至于引發新的技術革命,而真正推動REST發展的是移動網際網路的出現。由于多終端裝置的相容性需求,從前的服務端渲染已經很難滿足要求了。服務端不可能針對每一個Client渲染一套界面,如果服務端隻提供需要的資料,而具體界面的渲染完全交給具體的Client來完成,是以催生了REST的發展和普及。

RESTful可以通過一套統一的接口為 Web、iOS和Android提供服務,另外對于很多平台來說(比如像Facebook,Twiter、微網誌、微信等開放平台),它們不需要有顯式的前端,隻需要一套提供服務的接口,于是RESTful便是它們最好的選擇。

資深技術專家楊彪:你真的了解REST嗎?小結

REST API

前端渲染和後端渲染的優勢是什麼

随着前端渲染引擎的發展,新興的Angular,React,Vue等的出現,真正地實作了前後端分離解耦:前端專注于UI,負責View和Controller層,後端專注于業務/資料處理,負責Model層,兩端通過設計好的REST API進行互動。

資深技術專家楊彪:你真的了解REST嗎?小結

圖檔來自阿裡玉伯的文章

參考文章

https://github.com/lifesinger/blog/issues/184

https://wenku.baidu.com/view/4c7b010c17fc700abb68a98271fe910ef12dae01

雖然現在前後端分離早已不是什麼新鮮話題,不過前後端分離到底有什麼樣的優勢呢?我們可以對比一下各自的優點。

後端渲染的優點:

 ●  1、對搜尋引擎友好,這樣做有利于 SEO。

 ●  2、加載時間短,後端渲染加載完成後就直接顯示HTML,但前端渲染在加載完成後還需要有段js 渲染的時間。

前端渲染的優點:

 ●  1、讓前後端的職責更清晰,分工更合理高效。前後端業務分離,後端隻需要提供資料接口,前端在開發時也不需要部署對應的後端環境,可以通過Mock資料進行并發開發。

 ●  2、計算量轉移,原本由伺服器執行的渲染任務轉移給了用戶端,這在大量使用者通路的時候大大減輕後端的壓力。讓後端專注做後端應該做的事情,性能将大大提高,因為伺服器做的事情确實減小了。

前後端分離+Node層優點:

 ●  通過 Node,Web Server 層也是 JavaScript 代碼,這意味着部分代碼可前後複用,需要 SEO 的場景可以在服務端同步渲染,由于異步請求太多導緻的性能問題也可以通過服務端來緩解,結合了前兩種模式的優點。

言歸正傳,前面介紹了什麼是REST,也介紹了它的優勢,接下來詳細介紹REST的具體内容。

什麼樣的REST才是『正宗』的

無狀态原則

遵循REST範式的系統是無狀态的,這意味着伺服器不需要知道用戶端處于什麼狀态,反之亦然。這樣,即使沒有看到以前的消息,伺服器和用戶端都可以了解收到的任何消息。這種的無狀态限制是通過使用資源來實作的。資源是Web中的特定名詞——它描述了任何你可能需要存儲或發送到其他服務的對象或文檔。

無狀态原則是RESTful架構設計中一個非常重要的原則,無狀态是相對于有狀态而言的,我們首先看一下什麼是有狀态的。

Web服務的狀态一般指的是請求的狀态,是用戶端和服務端進行互動操作時所留下來的公共資訊(比如,使用者的資訊等)。這些資訊可以被指定在不同的作用域中(如request、session、application等),通常由服務端來儲存這些資訊。

而無狀态的Web服務是指每一個Web請求都是獨立的,服務端沒有儲存任何用戶端的狀态資訊,是以用戶端發送的請求必須包含有能夠讓服務端了解請求的全部資訊。

另外由于REST系統通過資源上的标準操作進行互動,是以它們不依賴于接口的實作,使得RESTful應用程式具有可靠性、快速性和可擴充性。

前後端通信機制

1、請求方式

REST要求用戶端向服務端送出請求以獲得或修改伺服器上的資料。請求通常由以下部分組成:

 ●  一個HTTP動詞,它定義了要執行的操作類型

 ●  一個頭部,它允許用戶端傳遞關于請求的資訊

 ●  一條資源的路徑

 ●  一個包含資料的可選消息主體

(1)對于HTTP動詞

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

 ●  GET - 檢索特定資源(通過id)或資源集合

 ●  POST - 建立一個新資源

 ●  PUT - 更新特定資源(通過ID)

 ●  DELETE - 按ID删除特定資源

(2)對于請求頭部

用戶端向服務端發送它能夠接收的内容的類型,而該類型是通過一個叫Accept的字段發送的。通過這種方式可以確定服務端不會發送用戶端無法了解或者無法處理的資料。

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

例如,包含HTML的文本檔案類型指定為text/html,而包含CSS的文本檔案需要指定為text/css,一般的文本檔案将被指定為text/plain(如果不指定,則預設值為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中,每一個請求的動作都必須作用于一個資源路徑上,是以資源路徑的設計就是為了讓用戶端能夠了解它所進行的操作是什麼。

通常情況下,路徑的第一部分應該是資源的複數形式。RESTful中這種路徑嵌套方式簡單易讀,也更容易了解。示例如下:

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

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

路徑必須包含它所需要的能夠準确定位它所代表的資源位置的資訊。但是,如果引用的資源為清單或集合時,就不需要再向POST請求添加id這樣的唯一辨別了,因為在服務端将為該新對象生成一個唯一辨別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、接收内容

在伺服器向用戶端發送資料有效載荷的情況下,伺服器必須content-type在響應的頭部包含一個。這個content-type頭域告訴用戶端它在響應主體中發送的資料的類型。這些内容類型是MIME類型,就像它們在accept請求頭的字段中一樣。該content-type伺服器在響應發送回應的客戶機中指定的選項之一accept的請求的字段。

例如,當用戶端使用此GET請求通路具有資源id23的articles資源時:

GET /articles/23 HTTP/1.1

Accept: text/html, application/xhtml

伺服器可能會使用響應頭發回内容:

HTTP/1.1 200 (OK)

Content-Type: text/html

這将意味着所請求的内容被傳回的響應體用content-type的text/html,該客戶表示,将能夠接受。

3、傳回狀态

Accept: text/html, application/xhtml

Content-Type: text/html

來自伺服器的響應包含狀态代碼,以提醒客戶有關操作成功的資訊。作為開發人員,您不需要知道每個狀态代碼(其中有很多),但您應該知道最常見的狀态代碼以及它們的使用方式:

狀态碼 含義
200 (OK) 這是成功HTTP請求的标準響應。
201 (CREATED) 這是導緻成功建立項目的HTTP請求的标準響應。
204 (NO CONTENT) 這是成功HTTP請求的标準響應,響應正文中沒有任何内容被傳回。
400 (BAD REQUEST) 由于請求文法錯誤,大小過大或其他用戶端錯誤,無法處理該請求。
403 (FORBIDDEN) 用戶端沒有權限通路此資源。
404 (NOT FOUND) 此時無法找到該資源。它可能已被删除,或尚不存在。
500 (INTERNAL SERVER ERROR) 如果沒有更多可用的特定資訊,則通用答案意外失敗。

對于每個HTTP動詞,伺服器在成功時應傳回預期的狀态代碼:

 ●  GET - 傳回200(OK)。

 ●  POST - 傳回201(建立)。

 ●  PUT - 傳回200(OK)。

 ●  DELETE - 傳回204(無内容)。如果操作失敗,則傳回可能對應于遇到的問題的最具體的狀态碼。

4、CRUD示例說明

現在我們需要設計一個班級管理的系統,其中需要有班級資訊和班級的學生資訊。那我們該怎麼為它設計REST接口呢?可以按照以下幾點思考:

 ●  使用什麼樣的請求方式?

 ●  服務端傳回是什麼樣的?

 ●  通過什麼樣的

content-type

傳輸内容?

 ●  首先定義班級和學生的資料模型如下。

{

“class”: { "id": <Integer>,

“name”: <String>,

}

“num”: <Integer>

}

“ student”: {

"id": <Integer>,

“name”: <String>,

“age”: <Integer>

}

}

 ●  接口請求/響應的定義。

GET請求:

接口 請求方式 傳輸格式(Content-type) 傳回狀态
/classes GET application/json
/classes/:id
/classes/:id/students
/classes/:id/students/:id

POST請求:

POST

PUT請求:

PUT

DELETE請求:

DELETE

小結

本文介紹了REST的相關概念,同時介紹了我們為什麼需要REST,分析了前端渲染和後端渲染的優勢是什麼,然後再介紹了什麼樣的REST才是"正宗"的,最後通過一個示例完整的示範了CRUD的操作。

原文釋出時間為:2018-11-2

本文作者:楊彪@雲技術架構

本文來自雲栖社群合作夥伴“

中生代技術

”,了解相關資訊可以關注“

”。

繼續閱讀