Restful軟件架構(gòu)風(fēng)格簡(jiǎn)述

前言

前后端分離已經(jīng)是業(yè)界所共識(shí)的一種開發(fā)/部署模式了。前端和后端人員的分工越來越明確,他們之間如何協(xié)同工作變得越來越重要。這種模式下,我們通過API來解耦前端和后端開發(fā)過程。因此API是前后端必須共同理解的語(yǔ)言。雙方只需要約定數(shù)據(jù)接口,而不必在代碼層面有任何的耦合。預(yù)先確定一個(gè)雙方都能夠理解的編程風(fēng)格是前后端分離非常重要的一環(huán)。

什么是restful編程風(fēng)格

220px-Roy_Fielding.jpg

Fielding博士的那篇經(jīng)典論文中文版)對(duì)萬(wàn)維網(wǎng)架構(gòu)的貢獻(xiàn)可謂是居功至偉??上攵?,當(dāng)REST一詞變得流行起來之后,其濫用甚至是“掛羊頭賣狗肉”的現(xiàn)象是不可避免的。而糟糕的是,對(duì)于那些沒有時(shí)間、也沒有耐心去仔細(xì)閱讀該論文的人來說,可能就會(huì)在看過或用過某些號(hào)稱具有REST風(fēng)格的應(yīng)用之后對(duì)REST本身產(chǎn)生錯(cuò)誤的理解,進(jìn)而在錯(cuò)誤的思想指導(dǎo)之下錯(cuò)誤地運(yùn)用REST。這正是其創(chuàng)造者本身所不愿意看到的。

Wikipedia: 表征性狀態(tài)傳輸(英文:Representational State Transfer,簡(jiǎn)稱REST)是Roy Fielding博士于2000年在他的博士論文中提出來的一種軟件架構(gòu)風(fēng)格。

Roy Fielding是HTTP協(xié)議(1.0版和1.1版)的主要設(shè)計(jì)者,事實(shí)上HTTP 1.1規(guī)范正是基于REST架構(gòu)風(fēng)格的指導(dǎo)原理來設(shè)計(jì)的。需要注意的是,REST是一種設(shè)計(jì)風(fēng)格而不是標(biāo)準(zhǔn),如果一個(gè)架構(gòu)符合REST原則,我們就稱它為RESTful架構(gòu)。

為什么要寫成restful風(fēng)格


在「遠(yuǎn)古時(shí)代」前端后端是融合在一起的,比如之前的PHP,JSP,ASP等等。近年來隨著移動(dòng)互聯(lián)網(wǎng)的飛速發(fā)展,各種類型的Client端層出不窮,就需要通過一套統(tǒng)一的接口分別為Web,iOS和Android乃至桌面端提供服務(wù)。另外對(duì)于廣大平臺(tái)來說,比如Facebook platform,微博開放平臺(tái),微信公共平臺(tái)等,它們不需要有顯式的前端,只需要一套提供服務(wù)的接口,于是RESTful更是它們最好的選擇。

理解REST三要素

  • Resource:資源,即數(shù)據(jù)。比如newsfeed,friends,order等;
  • Representational:某種表現(xiàn)形式,比如用JSON,XML,JPEG等;
  • State Transfer:狀態(tài)變化。通過HTTP動(dòng)詞實(shí)現(xiàn)。
20150117210140681.png

然后再來理解一個(gè)具體的RESTful架構(gòu)——面向資源的架構(gòu)(Resource-Oriented Architecture,ROA):
資源是由URI來指定。所謂「上網(wǎng)」,就是與互聯(lián)網(wǎng)上一系列的「資源」互動(dòng),調(diào)用它的URI。
對(duì)資源的操作包括獲取、創(chuàng)建、修改和刪除資源,這些操作正好對(duì)應(yīng)HTTP協(xié)議提供的GET、POST、PUT和DELETE方法。
通過操作資源的表現(xiàn)形式來操作資源。具體表現(xiàn)形式,應(yīng)該在HTTP請(qǐng)求的頭信息中用Accept和Content-Type字段指定。
資源的表現(xiàn)形式則是XML或者HTML,取決于讀者是機(jī)器還是人,是消費(fèi)web服務(wù)的客戶軟件還是web瀏覽器。當(dāng)然也可以是任何其他的格式。

怎樣做

應(yīng)用于Web服務(wù),符合REST設(shè)計(jì)風(fēng)格的Web API稱為RESTful API。它從以下三個(gè)方面資源進(jìn)行定義:
直觀簡(jiǎn)短的資源地址:URI,比如:http://example.com/resources/
;每一個(gè)URI代表一種資源;
傳輸?shù)馁Y源:Web服務(wù)接受與返回的互聯(lián)網(wǎng)媒體類型,比如:JSON,XML,YAML等。
對(duì)資源的操作:Web服務(wù)在該資源上所支持的一系列請(qǐng)求方法(比如:POST,GET,PUT或DELETE)。

來個(gè)圖,


Restful API設(shè)計(jì)要點(diǎn)

1.使用名詞而不是動(dòng)詞

Resource
資源

GET讀
POST創(chuàng)建
PUT修改
DELETE刪除

/cars 返回 cars集合 創(chuàng)建新的資源 批量更新cars 刪除所有cars
/cars/711 返回特定的car 該方法不允許(405) 更新一個(gè)指定的資源 擅長(zhǎng)指定資源

不要使用:
/getAllCars
/createNewCar
/deleteAllRedCars

2.Get方法和查詢參數(shù)不應(yīng)該涉及狀態(tài)改變

使用PUT, POST 和DELETE 方法 而不是 GET 方法來改變狀態(tài),不要使用GET 進(jìn)行狀態(tài)改變:

GET /users/711?activate
GET /users/711/activate

3.使用復(fù)數(shù)名詞

不要混淆名詞單數(shù)和復(fù)數(shù),為了保持簡(jiǎn)單,只對(duì)所有資源使用復(fù)數(shù)。

/cars 而不是 /car
/users 而不是 /user
/products 而不是 /product
/settings 而部署 /setting

4. 使用子資源表達(dá)關(guān)系

如果一個(gè)資源與另外一個(gè)資源有關(guān)系,使用子資源:

GET /cars/711/drivers/ 返回 car 711的所有司機(jī)
GET /cars/711/drivers/4 返回 car 711的4號(hào)司機(jī)

5.使用Http頭聲明序列化格式

在客戶端和服務(wù)端,雙方都要知道通訊的格式,格式在HTTP-Header中指定

Content-Type 定義請(qǐng)求格式
Accept 定義系列可接受的響應(yīng)格式

6.使用HATEOAS

Hypermedia as the Engine of Application State 超媒體作為應(yīng)用狀態(tài)的引擎,超文本鏈接可以建立更好的文本瀏覽:

{
"id": 711,
"manufacturer": "bmw",
"model": "X5",
"seats": 5,
"drivers": [
{
"id": "23",
"name": "Stefan Jauker",
"links": [
{
"rel": "self",
"href": "/api/v1/drivers/23"
}
]
}
]
}
注意href指向下一個(gè)URL

7.為集合提供過濾 排序 選擇和分頁(yè)等功能

Filtering過濾:

使用唯一的查詢參數(shù)進(jìn)行過濾:

GET /cars?color=red 返回紅色的cars
GET /cars?seats<=2 返回小于兩座位的cars集合

Sorting排序:

允許針對(duì)多個(gè)字段排序

GET /cars?sort=-manufactorer,+model

這是返回根據(jù)生產(chǎn)者降序和模型升序排列的car集合

Field selection

移動(dòng)端能夠顯示其中一些字段,它們其實(shí)不需要一個(gè)資源的所有字段,給API消費(fèi)者一個(gè)選擇字段的能力,這會(huì)降低網(wǎng)絡(luò)流量,提高API可用性。

GET /cars?fields=manufacturer,model,id,color

Paging分頁(yè)

使用 limit 和offset.實(shí)現(xiàn)分頁(yè),缺省limit=20 和offset=0;

GET /cars?offset=10&limit=5

為了將總數(shù)發(fā)給客戶端,使用訂制的HTTP頭: X-Total-Count.

鏈接到下一頁(yè)或上一頁(yè)可以在HTTP頭的link規(guī)定,遵循Link規(guī)定:

Link: https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5; rel="next",
https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3; rel="last",
https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5; rel="first",
https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5; rel="prev",

8.版本化你的API

使得API版本變得強(qiáng)制性,不要發(fā)布無(wú)版本的API,使用簡(jiǎn)單數(shù)字,避免小數(shù)點(diǎn)如2.5.

一般在Url后面使用?v

/blog/api/v1

9. 使用Http狀態(tài)碼處理錯(cuò)誤

如果你的API沒有錯(cuò)誤處理是很難的,只是返回500和出錯(cuò)堆棧不一定有用

Http狀態(tài)碼提供70個(gè)出錯(cuò),我們只要使用10個(gè)左右:

200 – OK – 一切正常
201 – OK – 新的資源已經(jīng)成功創(chuàng)建
204 – OK – 資源已經(jīng)成功擅長(zhǎng)

304 – Not Modified – 客戶端使用緩存數(shù)據(jù)

400 – Bad Request – 請(qǐng)求無(wú)效,需要附加細(xì)節(jié)解釋如 "JSON無(wú)效"
401 – Unauthorized – 請(qǐng)求需要用戶驗(yàn)證
403 – Forbidden – 服務(wù)器已經(jīng)理解了請(qǐng)求,但是拒絕服務(wù)或這種請(qǐng)求的訪問是不允許的。
404 – Not found – 沒有發(fā)現(xiàn)該資源
422 – Unprocessable Entity – 只有服務(wù)器不能處理實(shí)體時(shí)使用,比如圖像不能被格式化,或者重要字段丟失。

500 – Internal Server Error – API開發(fā)者應(yīng)該避免這種錯(cuò)誤。

使用詳細(xì)的錯(cuò)誤包裝錯(cuò)誤:

{
"errors": [
{
"userMessage": "Sorry, the requested resource does not exist",
"internalMessage": "No car found in the database",
"code": 34,
"more info": "http://dev.mwaysolutions.com/blog/api/v1/errors/12345"
}
]
}

10.允許覆蓋http方法

一些代理只支持POST 和 GET方法, 為了使用這些有限方法支持RESTful API,需要一種辦法覆蓋http原來的方法。

使用訂制的HTTP頭 X-HTTP-Method-Override 來覆蓋POST 方法.

冪等性安全性

HTTP動(dòng)詞
HTTP并沒有定義很多動(dòng)詞來描述web服務(wù)中可能出現(xiàn)的行為,它只用了一個(gè)標(biāo)準(zhǔn)動(dòng)詞集合來處理各種相似情況,從而讓API變得更直觀。每個(gè)動(dòng)詞通過兩種屬性的組合來滿足不同的場(chǎng)景需求。
冪等性:操作可以被重復(fù)執(zhí)行,就算在失敗以后。

安全性:對(duì)客戶端來說操作不會(huì)產(chǎn)生副作用。

GET --冪等、安全
用來從服務(wù)器端讀取狀態(tài)。這個(gè)操作是安全的,所以它可以被執(zhí)行很多次而不會(huì)對(duì)數(shù)據(jù)有任何影響,也就是說執(zhí)行它一次跟執(zhí)行十次是一樣的效果。從冪等性方面來看,多次請(qǐng)求跟單個(gè)請(qǐng)求總能得到相同的結(jié)果。
POST
一般用來在服務(wù)器端創(chuàng)建某種狀態(tài)。這個(gè)操作不具備冪等性跟安全性,所以多次請(qǐng)求會(huì)在服務(wù)器端創(chuàng)建多個(gè)資源。因?yàn)镻OST是不冪等的, 所以不應(yīng)該被用來做跟金錢有關(guān)系的操作,試想一次失敗的請(qǐng)求如果被執(zhí)行多次,那么很可能轉(zhuǎn)賬或者支付也被執(zhí)行了多次。
PUT
雖然它也可以被用來創(chuàng)建狀態(tài),但主要還是用來在服務(wù)器端更新狀態(tài)的。它是冪等的,但不安全,因?yàn)樗鼤?huì)改變服務(wù)端的狀態(tài)。因?yàn)樗膬绲刃?,PUT可以被用來處理跟金錢有關(guān)系的操作。
DELETE
用來在服務(wù)器端刪除狀態(tài)。它也是冪等非安全的,因?yàn)樗鼤?huì)移除服務(wù)端的狀態(tài)。它之所以是冪等的,是因?yàn)橹貜?fù)刪除一個(gè)狀態(tài)的結(jié)果是一樣。

是否一定要用REST

前面說了這么多REST,最后再冷靜下來思考一下,是否一定要用REST,是否一定要嚴(yán)格遵循REST設(shè)計(jì)風(fēng)格。
引用知乎作者淘李福的話
REST本身不是架構(gòu),只是一種架構(gòu)風(fēng)格,理解它的時(shí)候要參考這個(gè)架構(gòu)風(fēng)格出現(xiàn)的環(huán)境所施加的約束條件。
REST的目的是“建立十年內(nèi)不會(huì)過時(shí)的軟件系統(tǒng)架構(gòu)",所以它具備三個(gè)特點(diǎn):

  1. 狀態(tài)無(wú)關(guān) —— 確保系統(tǒng)的橫向拓展能力
  2. 超文本驅(qū)動(dòng),F(xiàn)ielding的原話是”hypertext-driven" —— 確保系統(tǒng)的演化能力
  3. 對(duì) resource 相關(guān)的模型建立統(tǒng)一的原語(yǔ),例如:uri、http的method定義等 —— 確保系統(tǒng)能夠接納多樣而又標(biāo)準(zhǔn)的客戶端
    從另外一個(gè)角度看,第一條保證服務(wù)端演化,第三條保證客戶端演化,第二條保證應(yīng)用本身的演化,這實(shí)在是一個(gè)極具抽象能力的方案。

引用列表
https://en.wikipedia.org/wiki/Roy_Fielding
https://blog.jimmylv.info/2015-11-11-what-is-really-rest/
http://www.jdon.com/soa/10-best-practices-for-better-restful-api.html
https://www.oschina.net/translate/what-does-restful-really-mean

https://www.zhihu.com/question/33959971/answer/60280136

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一說到REST,我想大家的第一反應(yīng)就是“啊,就是那種前后臺(tái)通信方式?!钡窃谝笤敿?xì)講述它所提出的各個(gè)約束,以及如...
    時(shí)待吾閱讀 3,601評(píng)論 0 19
  • 原文鏈接:https://https://howardwchen.com/2017/09/18/talk-abou...
    守望者Howard閱讀 6,570評(píng)論 1 6
  • 傳統(tǒng)文化是由“傳統(tǒng)”和“文化”兩個(gè)概念復(fù)合而成,首先讓我們看一看“傳統(tǒng)”和“文化”這兩個(gè)概念。 關(guān)于傳統(tǒng) ...
    子正書院閱讀 2,269評(píng)論 0 7
  • 世間有個(gè)好男人,我以前做錯(cuò)了很多,甚至在意別人的眼光,我不懂他,也沒有好好愛他,可是他很愛很愛我。只是后來,他用離...
    ec5f3419bfea閱讀 414評(píng)論 0 1
  • 今天是第二十天,對(duì)于時(shí)間管理更多的是來自于書以及來自別人口中的時(shí)間管理。然而,他們的時(shí)間管理從來不是我的時(shí)間管理,...
    酸酸酸酸酸奶閱讀 208評(píng)論 0 0

友情鏈接更多精彩內(nèi)容