摘要
本文介紹了 REST 的由來强缘,對 REST 的風(fēng)格架構(gòu)設(shè)計指導(dǎo)原則做了詳細(xì)的說明。同時舉例了過往開發(fā)中若干細(xì)節(jié)的考慮和實現(xiàn)方案咕缎。
文字略長外厂,預(yù)計需要10 ~ 20?分鐘讀完。也可以收藏起來豌骏,在需要的時候查閱龟梦。
RESTful ?架構(gòu)是目前流行的一種互聯(lián)網(wǎng)應(yīng)用架構(gòu)。如果把網(wǎng)站窃躲,移動應(yīng)用從服務(wù)器到前端计贰,從整體上看作是一個軟件,它就是一個層次清楚框舔,功能強(qiáng)蹦玫,擴(kuò)展方便,適宜通信的架構(gòu)規(guī)范刘绣。
·?01?·
什么是 REST
REST 是 “Representational State Transfer”的縮寫樱溉,直譯過來就是“表述性狀態(tài)轉(zhuǎn)移”。這是一個很奇怪的名詞纬凤,剛看到的時候福贞,不知其所以然。這個名詞來源于 Roy Thomas Fielding 博士著名的論文《Architectural Styles and the Design of Network-based Software Architectures》(架構(gòu)風(fēng)格與基于網(wǎng)絡(luò)的軟件架構(gòu)設(shè)計)停士。
論文發(fā)表于2000年挖帘,作者在基于 REST 的約束上設(shè)計了 HTTP 協(xié)議。設(shè)計 REST 的目的恋技,就是為了指導(dǎo)現(xiàn)代 Web 架構(gòu)的設(shè)計與開發(fā)拇舀。他是 HTTP 協(xié)議(1.0 版和 1.1 版)的主要設(shè)計者、Apache 服務(wù)器軟件的作者之一蜻底、Apache 基金會的第一任主席骄崩。
論文的第六章,作者解釋了這個名詞的由來:
REST 最初被?稱作“HTTP 對象模型”薄辅,但是那個名稱常常引起誤解要拂,使人們誤以為它是一個 HTTP 服務(wù)?器的實現(xiàn)模型。這個名稱“表述性狀態(tài)轉(zhuǎn)移”是有意喚起人們對于一個良好設(shè)計的 Web 應(yīng)?用如何運轉(zhuǎn)的印象:一個由網(wǎng)頁組成的網(wǎng)絡(luò)(一個虛擬狀態(tài)機(jī))站楚,用戶通過選擇鏈接(狀態(tài)轉(zhuǎn)移)在應(yīng)用中前進(jìn)脱惰,導(dǎo)致下一個頁面(代表應(yīng)用的下一個狀態(tài))被轉(zhuǎn)移給用戶,并且呈現(xiàn)給他們窿春,以便他們來使用拉一。
第四章描述了設(shè)計 REST 的動機(jī):“為 Web 應(yīng)該如何運轉(zhuǎn)創(chuàng)建一種架構(gòu)模型采盒, 使之成為 Web 協(xié)議標(biāo)準(zhǔn)的指導(dǎo)框架”。第五章從一個沒有約束的空架構(gòu)開始舅踪,不斷的添加約束纽甘,從而使此架構(gòu)進(jìn)化為 Web 所需要的架構(gòu)。
所以抽碌,REST 是一組架構(gòu)約束悍赢。
REST 約束包括:客戶-服務(wù)器,無狀態(tài)货徙,緩存左权,統(tǒng)一接口,分層系統(tǒng)痴颊,按需代碼赏迟。如果一個架構(gòu)符合 REST 原則,就稱它為 RESTful 架構(gòu)蠢棱。
為實現(xiàn)統(tǒng)一的接口锌杀,REST由四個接口約束來定義:
資源的識別(identification of resources)、
通過表述對資源執(zhí)行的操作(manipulation of resources through representations)泻仙、
自描述的消息(self-descriptive messages)糕再、
應(yīng)用狀態(tài)引擎的超媒體(hypermedia as the engine of application state,HEOAS)玉转。
當(dāng)我們用這個原則來設(shè)計服務(wù)器端的接口突想,為前端或者外部提供數(shù)據(jù)時,就稱它為 RESTful ?API 究抓。目前觀察到猾担,業(yè)內(nèi)在實踐中有下面這些指導(dǎo)原則:
用統(tǒng)一資源標(biāo)識符來標(biāo)識資源
應(yīng)用狀態(tài)引擎的超媒體(HEOAS)
使用標(biāo)準(zhǔn)的 HTTP 方法
安全性和冪等性
無狀態(tài)性
在實際開發(fā)過程中,我們還會涉及下面幾個方面:
版本
鑒權(quán)
常見場景
狀態(tài)碼和錯誤處理
返回結(jié)果
文檔
在 REST 出現(xiàn)之前刺下,程序間的網(wǎng)絡(luò)通信架構(gòu)采用的是遠(yuǎn)程過程調(diào)用(Remote Procedure Call绑嘹,RPC),而后又在 RPC 基礎(chǔ)上發(fā)展出來簡單對象訪問協(xié)議( Simple Object Access Protocol橘茉,SOAP)圾叼,此后,出現(xiàn)了 REST捺癞。
REST 是一種面向資源的架構(gòu),它能更好的適應(yīng)分布式下的系統(tǒng)架構(gòu)設(shè)計构挤。對于開發(fā)者來說髓介,越來越簡單,越來越靈活筋现。
·?02?·
什么是資源
資源是一種概念上的映射唐础。
任何能夠被命名的信息都能夠作為一個資源箱歧,它是對信息的核心抽象:一份文檔、一張圖片一膨、一個與時間相關(guān)的服務(wù)(例如:“我現(xiàn)在城市的天氣”)呀邢、一個包含其他資源的集合、一個非虛擬的對象(例如:用戶)等等豹绪。它是到一組實體的概念上的映射价淌,而不是實體本身。
更精確地說瞒津,資源 R 是一個隨時間變化的成員函數(shù) MR(t)蝉衣,該函數(shù)將時間 t 映射到等價的一個實體或值的集合,集合中的值可能是資源的表述和巷蚪,或資源的標(biāo)識符病毡。
資源不是存儲對象,也不是單個文件屁柏,更不是某個文本啦膜、音頻、視頻等具體事物淌喻。
在設(shè)計具體 API 的時候僧家,資源是業(yè)務(wù)系統(tǒng)里,抽象出來的一個業(yè)務(wù)對象似嗤。例如:用戶(User)啸臀,訂單(Order),令牌(Token)等等烁落。它允許隨時間變化乘粒,輸出不同值。
一個資源具有一個或者多個標(biāo)識伤塌。這里說的標(biāo)識就是統(tǒng)一資源標(biāo)識符(Uniform Resource Identifier灯萍,URI)。統(tǒng)一資源定位符(Uniform Resource Locator每聪,URL)則是 URI 的一種具體實現(xiàn)旦棉,是 URI 的子集。在通常的 API 設(shè)計中药薯,直接使用 URL 來標(biāo)示應(yīng)用系統(tǒng)中的資源绑洛。
例如:
https://www.sample.com/api/shops/10083 - 編號10083店鋪的基本信息
https://www.sample.com/api/users/2372/orders - 編號2372用戶的所有訂單信息
在標(biāo)準(zhǔn)的 REST 規(guī)范觀點中,通常會要求將資源 shop 加上復(fù)數(shù)形式 s 表示多個資源童本。但現(xiàn)實中真屯,很多時候忘記給獲取多個資源的接口加上復(fù)數(shù)形式,在不影響理解的前提下穷娱,這種做法也不是不可以接受绑蔫。
實踐中常見的情況有:
移動應(yīng)用的首頁运沦,通常有多種資源:橫幅廣告、編輯精選的內(nèi)容配深、針對當(dāng)前用戶推薦的商品携添,相應(yīng)的對應(yīng)著三個資源:廣告(banners),內(nèi)容(contents)篓叶,商品(products)烈掠。
通常后端的開發(fā)會讓前端調(diào)用這三個資源的接口,獲得相應(yīng)的數(shù)據(jù)澜共。但是前端開發(fā)會要求向叉,后端能不能針對首頁單獨給一個接口?
為適應(yīng)這種情況嗦董,我們會創(chuàng)建一個首頁的資源:index母谎,這個資源包括需要展示的其他子資源。如:
https://www.sample.com/api/indexs京革。
幾乎所有的應(yīng)用奇唤,都會有一個搜索功能。我們很容易習(xí)慣性的設(shè)計這樣的接口:
https://www.sample.com/users/search?key=searchkey匹摇。
這樣的接口設(shè)計就沿襲了 RPC 的設(shè)計風(fēng)格咬扇,表示 users 服務(wù)提供的 search 方法,不符合 REST 規(guī)范廊勃,也是規(guī)范里建議的懈贺,URI中不要有動詞。因為"資源"表示一種實體坡垫,所以應(yīng)該是名詞梭灿,URI不應(yīng)該有動詞,動詞應(yīng)該放在HTTP協(xié)議中冰悠。
推薦的做法是設(shè)計一個資源 search堡妒,也就是說把動詞變成資源。例如:
https://www.sample.com/search/?key=searchkey&source=user
https://www.sample.com/search/user?key=searchkey
·?03?·
應(yīng)用狀態(tài)引擎的超媒體(HEOAS)
這個名詞也非常的拗口溉卓。它實際的意思是皮迟,在資源的表述中,如果有其他資源的桑寨,則會提供相應(yīng)的鏈接 URL伏尼,使得用戶不查文檔,也知道如何獲得相關(guān)的資源尉尾。
Fielding 明確表示烦粒,系統(tǒng)必須滿足 HATEOAS 約束才能稱為是符合 REST 風(fēng)格的。
Github 的 API 就是這種設(shè)計,訪問 api.github.com 會得到一個所有可用的 API 的信息列表扰她,類似這樣:
{?
?"current_user_url": "https://api.github.com/user",?
?"current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}",?
?"authorizations_url": "https://api.github.com/authorizations",?
?...?
}
所以?HATEOAS 會被稱為狀態(tài)引擎,因為它會引導(dǎo)狀態(tài)的轉(zhuǎn)移芭碍。
在設(shè)計的理想狀態(tài)中徒役,使用 HATEOAS 的 REST 服務(wù)中,客戶端可以通過服務(wù)器提供的資源的表達(dá)來智能地發(fā)現(xiàn)可以執(zhí)行的操作窖壕。當(dāng)服務(wù)器發(fā)生了變化時忧勿,客戶端并不需要做出修改,因為資源的 URI 和其他信息都是動態(tài)發(fā)現(xiàn)的瞻讽。
這樣的設(shè)計鸳吸,保證了客戶端和服務(wù)器的實現(xiàn)之間是松耦合的。客戶端需要根據(jù)服務(wù)器提供的返回信息來了解所暴露的資源和對應(yīng)的操作速勇。當(dāng)服務(wù)器端發(fā)生了變化時晌砾,如修改了資源的 URI,客戶端不需要進(jìn)行相應(yīng)的修改烦磁。
在實踐中养匈,我沒發(fā)現(xiàn)哪家國內(nèi)的公司公布的 API 的接口遵守了這條原則,我們自己開發(fā)時都伪,也不實現(xiàn)這條原則呕乎。為什么實際中大部分開發(fā)不遵守這條原則呢?
因為客戶端無法決策陨晶!
HTTP 能實現(xiàn) RESTful猬仁,是因為瀏覽器只是將表述以及對資源的操作選項展示了出來,至于具體該如何操作先誉,是由使用瀏覽器的人來決定的湿刽。也就是說,雖然服務(wù)端告訴了客戶端操作的可選項谆膳,但是客戶端沒辦法知道該選擇什么叭爱。網(wǎng)頁瀏覽是有人參與的,但是 RESTful API 沒有人參與漱病,導(dǎo)致 RESTful API 的客戶端難以做出決定买雾,該做什么。
鑒于現(xiàn)實這個尷尬情況杨帽,Richardson 提出了「REST成熟度模型」漓穿。該模型把 REST 服務(wù)按照成熟度劃分成 4 個層次:
Level 0:Web 服務(wù)只是使用 HTTP 作為傳輸方式,實際上只是遠(yuǎn)程方法調(diào)用(RPC)的一種具體形式注盈。SOAP 和 XML-RPC 都屬于此類晃危。?
Level 1:Web 服務(wù)引入了資源的概念。每個資源有對應(yīng)的標(biāo)識符和表述。?
Level 2:Web 服務(wù)使用不同的 HTTP 方法來進(jìn)行不同的操作僚饭,并且使用 HTTP 狀態(tài)碼來表示不同的結(jié)果震叮。如:HTTP GET 方法來獲取資源,HTTP DELETE 方法來刪除資源鳍鸵。?
Level 3:Web 服務(wù)使用 HATEOAS苇瓣。在資源的表述中包含了鏈接信息〕ス裕客戶端可以根據(jù)鏈接來發(fā)現(xiàn)可以執(zhí)行的動作击罪。
從成熟度模型中可以看到,使用 HATEOAS 的 REST 服務(wù)是成熟度最高的贪薪,也是推薦的做法媳禁。但實際的落地實現(xiàn)時,多數(shù)都是次一級的做法画切。
·?04?·
使用標(biāo)準(zhǔn)的 HTTP 方法
RESTful API 使用標(biāo)準(zhǔn)的 HTTP 協(xié)議實現(xiàn)前后端的接口調(diào)用竣稽。對涉及到的資源,常用的操作就是增槽唾、刪丧枪、改、查庞萍,類似對數(shù)據(jù)庫記錄的CRUD(Create拧烦,Read,Update钝计,Delete)恋博。使用的 HTTP 方法規(guī)則如下:
查詢?GET :GET ?/users/{userId}
增加?POST:POST ?/users
全量修改?PUT:PUT /users/{userId} ?即提供該用戶的所有信息來修改
部分修改?PATCH:PATCH /users/{userId}?只提供需要的修改的信息
刪除?DELETE:DELETE /users/{userId}
在修改的時,PUT 和 PATCH 區(qū)別在于 PUT 是全量修改私恬,user 資源有多少信息债沮,需要全部提供,而 PATCH 可以只修改手機(jī)或者郵箱本鸣,昵稱疫衩,密碼等信息。
HTTP 的方法中還有兩個涉及到 REST:HEAD 和 OPTIONS荣德。
HEAD 方法用于得到描述目標(biāo)資源的元數(shù)據(jù)信息闷煤。
例如,騰訊云的對象存儲的API:HEAD Bucket 請求可以確認(rèn)該存儲桶是否存在涮瞻,是否有權(quán)限訪問鲤拿。
請求:
HEAD / HTTP/1.1?
Host: <BucketName-APPID>.cos.<Region>.myqcloud.com?
Date: GMT Date?
Authorization: Auth String
服務(wù)器響應(yīng):
OPTIONS /exampleobject HTTP/1.1?
?Host: examplebucket-1250000000.cos.ap-beijing.myqcloud.com?
?Date: Thu, 12 Jan 2017 17:26:53 GMT?
?Origin: http://www.qq.com?
?Access-Control-Request-Method: PUT
OPTIONS 請求用來確定對某個資源必須具有怎樣的約束。
使用場景:客戶端先使用 OPTIONS 詢問服務(wù)端署咽,應(yīng)該采用怎樣的 HTTP 方法以及自定義的請求報頭近顷,然后根據(jù)其約束發(fā)送真正的請求。
例如,騰訊云的對象存儲 OPTIONS Object 接口實現(xiàn) Object 跨域訪問配置的預(yù)請求窒升。即在發(fā)送跨域請求之前會發(fā)送一個 OPTIONS 請求并帶上特定的來源域缀遍,HTTP 方法和 Header 信息等給 COS,以決定是否可以發(fā)送真正的跨域請求饱须。
請求:
OPTIONS /exampleobject HTTP/1.1?
Host: examplebucket-1250000000.cos.ap-beijing.myqcloud.com?
Date: Thu, 12 Jan 2017 17:26:53 GMT?
Origin: http://www.qq.com?
Access-Control-Request-Method: PUT
服務(wù)器響應(yīng):
HTTP/1.1 200 OK?
Content-Type: application/xml?
Content-Length: 16087?
Connection: keep-alive?
x-cos-request-id: NTg3NzRiZGRfYmRjMzVfM2Y2OF81N2YzNA==?
Date: Thu, 12 Jan 2017 17:26:53 GMT?
ETag: \"9a4802d5c99dafe1c04da0a8e7e166bf\"?
Access-Control-Allow-Origin: http://www.qq.com?
Access-Control-Allow-Methods: PUT?
Access-Control-Expose-Headers: x-cos-request-id
完全按 REST 指導(dǎo)原則采用標(biāo)準(zhǔn) HTTP 方法很美好瑟由。但是實踐中,各大平臺推出了內(nèi)置小程序冤寿,前端在調(diào)用小程序的 request 請求時,發(fā)現(xiàn)只支持 GET青伤、POST 方法督怜。
這種情況下,導(dǎo)致后端的 API 接口不得不做調(diào)整狠角,所有方法在設(shè)計之初就只用 GET/POST 方法号杠。
或者在已成型的系統(tǒng)中使用擴(kuò)展屬性:X-HTTP-Method-Override,一個非標(biāo)準(zhǔn)的HTTP協(xié)議頭丰歌,來繞過這個問題姨蟋。前端統(tǒng)一使用POST,在請求頭帶上這個非標(biāo)屬性立帖,服務(wù)端根據(jù)Header:X-HTTP-Method-Override眼溶,轉(zhuǎn)換成真正的 METHOD。
·?05?·
安全性和冪等性
在討論 RESTful API 接口設(shè)計時晓勇,會提到兩個基本的特性:“安全性”和“冪等性”堂飞。
安全性是指調(diào)用接口不對資源產(chǎn)生修改。
冪等性是指調(diào)用方法1次或N次對資源產(chǎn)生的影響結(jié)果都是相同的绑咱。
需要特別注意的是:這里冪等性指的是對資源產(chǎn)生的影響結(jié)果绰筛,而不是調(diào)用HTTP方法的返回結(jié)果。
常用 HTTP 方法的冪等性和安全性總結(jié):
從上述表格中可以看出描融,HTTP 方法的冪等性和安全性并不是同一個概念:
OPTONS铝噩、HEAD、GET 既是冪等也是安全的窿克,不修改資源骏庸,多次調(diào)用對資源的影響是相同的。
POST让歼、PATCH 既不冪等也不安全敞恋,修改了資源,同時多次調(diào)用時谋右,對資源影響是不同的硬猫,PATCH 的影響不同在于,每次的局部更新可能會導(dǎo)致資源不一樣。
PUT 是對資源的全量更新啸蜜,多次更新總是對資源影響是一致的坑雅,所以它是冪等,但不安全衬横。
DELETE 用于刪除資源裹粤,多次調(diào)用的情況下,都是刪除了資源蜂林,所以它是冪等遥诉,但不安全。
冪等性原本是數(shù)學(xué)中的含義噪叙,表達(dá)式的N次變換與1次變換的結(jié)果相同矮锈。為什么要在接口設(shè)計時,考慮冪等性睁蕾?
在實際的業(yè)務(wù)流程場景下苞笨,我們可能會碰到下面一些問題:
訂單創(chuàng)建接口,前端調(diào)用超時了子眶,但服務(wù)端已經(jīng)完成了訂單的創(chuàng)建瀑凝,然后前端顯示失敗,用戶又點了一次臭杰。
用戶完成了支付粤咪,服務(wù)端完成了扣錢操作,但前端超時了硅卢,用戶不知道射窒,又去支付了一次。
用戶發(fā)起一筆轉(zhuǎn)賬業(yè)務(wù)将塑,服務(wù)端已經(jīng)完成了扣款脉顿,接口響應(yīng)超時,調(diào)用方重試了一次点寥。
以上類似的場景艾疟,需要在設(shè)計接口時考慮冪等性。我們可以借鑒微信支付的接口方案來實現(xiàn)這類場景需要的冪等性敢辩。在支付之前蔽莱,需要調(diào)用一個接口生產(chǎn)預(yù)支付交易單,獲得一個交易單號戚长,隨后再針對這個交易單號完成支付盗冷。服務(wù)端確保一個交易單號只會被支付一次,這樣就保證了支付過程的冪等性同廉。
在對冪等性的理解上仪糖,有時候我們會有疑惑:服務(wù)端一般會有日志柑司、緩存或者數(shù)據(jù)表上的計數(shù)器、最后更新時間等锅劝。這樣上面說的 GET攒驰、PUT、DELETE 符合冪等性的方法就會導(dǎo)致這些數(shù)據(jù)內(nèi)容的變化故爵,是不是就不是冪等性的方法呢玻粪?
我認(rèn)為在這個冪等判斷問題上,還是要回到什么是資源的定義問題上來诬垂。服務(wù)端的日志劲室、緩存、計數(shù)標(biāo)志结窘、更新時間等痹籍,不屬于抽象出來的核心概念,也就是對資源沒有本質(zhì)上的影響晦鞋,這些方法仍然是冪等的。
·?06?·
無狀態(tài)性
客戶端與服務(wù)端的交互必須是無狀態(tài)的棺克,并在每一次請求中包含處理該請求所需的一切信息悠垛。服務(wù)端不需要在請求間保留應(yīng)用狀態(tài),只有在接受到實際請求的時候娜谊,服務(wù)端才會關(guān)注應(yīng)用狀態(tài)确买。
這種無狀態(tài)通信原則,使得服務(wù)端和中介能夠理解獨立的請求和響應(yīng)纱皆。在多次請求中湾趾,同一客戶端也不再需要依賴于同一服務(wù)器,方便實現(xiàn)高可擴(kuò)展和高可用性的服務(wù)端派草。
REST 只維護(hù)資源的狀態(tài)搀缠,并不維護(hù)客戶端狀態(tài),而且 HTTP 本身是無狀態(tài)的近迁。那如何在用戶登錄后艺普,和服務(wù)器之間傳遞用戶信息呢?
以前這類場景下的做法是使用 cookie 和 session鉴竭,兩者的區(qū)別在于歧譬,是存在客戶端還是服務(wù)端。這種設(shè)計搏存,就違反了無狀態(tài)通信的設(shè)計原則瑰步。實踐中,API 設(shè)計成在用戶登錄之后璧眠,服務(wù)端會返回客戶端一個用戶令牌(Token)缩焦,并帶有失效時間读虏,客戶端在后續(xù)的接口請求都會帶上這個令牌。
·?07?·
版本
API 上線運行后舌界,就會有版本升級的情況掘譬。在 API 設(shè)計中,如何體現(xiàn)不同的版本呻拌?有兩種通常的做法:
將版本號放入 URL
將版本號放在 HTTP 信息頭
兩種方法各有優(yōu)缺點:放在 URL 中葱轩,直觀,方便藐握。Github 就是這樣的方案靴拱。
網(wǎng)上也有另一種說法,就是不同版本的資源猾普,仍然還是資源的不同表現(xiàn)形式袜炕,所以 URL 應(yīng)該是同一個,版本號需要放在 HTTP 信息頭的 Accept 字段中初家。
本人比較推薦第一種方案偎窘,將版本號放在 URL 中,對前端的兼容性溜在、普適性更友好陌知。
·?08?·
鑒權(quán)
REST 設(shè)計原則并未提到有些需要權(quán)限的業(yè)務(wù)場景下應(yīng)該怎么做。在實踐中掖肋,推薦使用 OAuth 2.0 標(biāo)準(zhǔn)來實現(xiàn) API 的鑒權(quán)需要仆葡。具體如何實現(xiàn),篇幅可能需要比較長志笼,不在此贅述沿盅。
·?09?·
常見場景
業(yè)務(wù)系統(tǒng)總是復(fù)雜的,前面舉了一些資源的操作的例子纫溃,但是距離一個實用的系統(tǒng)還遠(yuǎn)遠(yuǎn)不夠腰涧。
例如需要對列表信息進(jìn)行約束。應(yīng)用在初始時只顯示開始的若干條記錄紊浩,等待用戶翻頁或者下拉操作后南窗,需要服務(wù)端從第幾頁開始,返回一頁多少條記錄郎楼。類似下面這樣:
?pageIndex=2&pageSize=20 // 指定返回第2頁的20條數(shù)據(jù)?
?start=200&limit=20 // 指定返回從第200條記錄開始的20條數(shù)據(jù)
如果不使用動詞万伤,原來用戶登錄接口 POST /user/login 這樣的應(yīng)該如何設(shè)計?
還是使用資源的思維呜袁,用戶登錄就是為了獲得身份認(rèn)證信息敌买,所以這個資源就是“認(rèn)證”,例如:
GET /authorize?username=xx&password=xx?
GET /token
· 10?·
錯誤處理和返回碼
REST 設(shè)計原則推薦使用 HTTP 狀態(tài)碼來返回服務(wù)端信息阶界。如下:
200 OK - [GET]:服務(wù)器成功返回用戶請求的數(shù)據(jù)虹钮。?
201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數(shù)據(jù)成功聋庵。?
202 Accepted - [*]:表示一個請求已經(jīng)進(jìn)入后臺排隊(異步任務(wù))?
?204 NO CONTENT - [DELETE]:用戶刪除數(shù)據(jù)成功。?
400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發(fā)出的請求有錯誤芙粱,服務(wù)器沒有進(jìn)行新建或修改數(shù)據(jù)的操作祭玉。?
401 Unauthorized - [*]:表示用戶沒有權(quán)限(令牌、用戶名春畔、密碼錯誤)脱货。?
403 Forbidden - [*] 表示用戶得到授權(quán)(與401錯誤相對),但是訪問是被禁止的律姨。?
404 NOT FOUND - [*]:用戶發(fā)出的請求針對的是不存在的記錄振峻,服務(wù)器沒有進(jìn)行操作,該操作是冪等的择份。?
406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式扣孟,但是只有XML格式)。?
410 Gone -[GET]:用戶請求的資源被永久刪除荣赶,且不會再得到的凤价。?
422 Unprocesable entity - [POST/PUT/PATCH] 當(dāng)創(chuàng)建一個對象時,發(fā)生一個驗證錯誤拔创。?
500 INTERNAL SERVER ERROR - [*]:服務(wù)器發(fā)生錯誤料仗,用戶將無法判斷發(fā)出的請求是否成功。
實踐過程中伏蚊,不推薦 API 設(shè)計采用上面的錯誤返回碼。這樣做的結(jié)果會把業(yè)務(wù)系統(tǒng)里面本身的錯誤狀態(tài)與 HTTP 協(xié)議本身的錯誤混淆起來格粪,有悖于架構(gòu)設(shè)計中分層的原則躏吊。例如:
前端收到一個 404 錯誤時,不清楚是服務(wù)端沒有這個接口帐萎,還是請求的業(yè)務(wù)系統(tǒng)中的對應(yīng)資源不存在比伏。
出現(xiàn) 403 錯誤時,是因為服務(wù)端部署出現(xiàn)了權(quán)限錯誤疆导,還是用戶的對請求的資源權(quán)限不夠赁项。
出現(xiàn) 500 錯誤時,是不是服務(wù)端的服務(wù)器問題澈段,還是創(chuàng)建資源時悠菜,不滿足業(yè)務(wù)系統(tǒng)的一些限制條件。
所以败富,在最終的實際運行的系統(tǒng)中悔醋,只保留了一個200狀態(tài)碼,表示服務(wù)端收到了請求兽叮,并做了處理芬骄,業(yè)務(wù)系統(tǒng)本身的錯誤返回信息在結(jié)果中體現(xiàn)猾愿。
·?11?·
返回結(jié)果
上一節(jié)說了服務(wù)端返回時 HTTP 狀態(tài)碼時統(tǒng)一使用 200,表示業(yè)務(wù)系統(tǒng)正常運行账阻。如果有系統(tǒng)的錯誤提示信息需要向調(diào)用者返回蒂秘,則在返回結(jié)果中統(tǒng)一定義。如下面是一個常見的返回對象:
{?
code: 0, //表示接口執(zhí)行是否成功淘太,0:成功姻僧,非0:某一類預(yù)先定義的失敗錯誤碼。?
data: object, // 返回的數(shù)據(jù)對象?
error: 'error descrtion message', // 返回碼有錯誤時琴儿,返回對錯誤描述性的文字段化,方便調(diào)用端處理?
}
調(diào)用端在處理錯誤返回信息時,也有兩種方案:
直接顯示服務(wù)端返回的錯誤信息
根據(jù)錯誤碼造成,前端自行定義和顯示更人性化的錯誤提示信息
第一種方案便于系統(tǒng)修改显熏,可以在不修改調(diào)用端的情況下,修改返回的顯示信息晒屎。
第二種方案對用戶更友好喘蟆,常見用于調(diào)用外部接口時,屏蔽掉讓用戶不明白的錯誤提示信息鼓鲁,顯示遇到錯誤時蕴轨,應(yīng)該如何處理的友好提示。
·?12?·
接口文檔
實際系統(tǒng)開發(fā)過程中骇吭,接口文檔也是非常重要的一環(huán)橙弱。如果單獨專門編輯接口文檔,時間一長燥狰,就會造成代碼和文檔的不一致情況棘脐。開發(fā)團(tuán)隊還需要專門費事費力的在代碼版本升級后,同時更新接口文檔龙致。所以最好的辦法蛀缝,就是寫代碼的時候,同時更新文檔目代。
如果使用 Spring boot 開發(fā)的朋友屈梁,可以使用 swagger 自動生成在線的接口文檔,并且支持自動生成調(diào)用參數(shù)榛了,在線測試開發(fā)好的接口在讶。
其他語言的文檔生成工具,可以試試 apidoc霜大。也是通過讀代碼中的約定格式的注釋真朗,自動生成 API 文檔,也支持在線測試調(diào)用僧诚。
以上遮婶,大致將 RESTful API 架構(gòu)設(shè)計原則做了一個框架性的介紹蝗碎,附帶介紹了具體項目實踐中的幾種落地的做法。
技術(shù)發(fā)展到現(xiàn)在旗扑,在具體的代碼實現(xiàn)上蹦骑,Java 的 Spring boot 框架已經(jīng)很成熟,能滿足所有 RESTful API 設(shè)計原則臀防。