理解RESTful API 架構(gòu)設(shè)計規(guī)范與實踐

RESTful API

摘要

本文介紹了 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 方法的冪等性和安全性

從上述表格中可以看出描融,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è)計原則臀防。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末眠菇,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子袱衷,更是在濱河造成了極大的恐慌捎废,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件致燥,死亡現(xiàn)場離奇詭異登疗,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嫌蚤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門辐益,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脱吱,你說我怎么就攤上這事智政∑兜迹” “怎么了名惩?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長怒炸。 經(jīng)常有香客問我宦搬,道長牙瓢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任床三,我火速辦了婚禮,結(jié)果婚禮上杨幼,老公的妹妹穿的比我還像新娘撇簿。我一直安慰自己,他們只是感情好差购,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布四瘫。 她就那樣靜靜地躺著,像睡著了一般欲逃。 火紅的嫁衣襯著肌膚如雪找蜜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天稳析,我揣著相機(jī)與錄音洗做,去河邊找鬼弓叛。 笑死,一個胖子當(dāng)著我的面吹牛诚纸,可吹牛的內(nèi)容都是我干的撰筷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼畦徘,長吁一口氣:“原來是場噩夢啊……” “哼毕籽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起井辆,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤关筒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后杯缺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒸播,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年夺谁,在試婚紗的時候發(fā)現(xiàn)自己被綠了廉赔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡匾鸥,死狀恐怖蜡塌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情勿负,我是刑警寧澤馏艾,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站奴愉,受9級特大地震影響琅摩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锭硼,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一房资、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧檀头,春花似錦轰异、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至廊镜,卻和暖如春牙肝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工配椭, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留虫溜,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓颂郎,卻偏偏與公主長得像吼渡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子乓序,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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

  • 一說到REST寺酪,我想大家的第一反應(yīng)就是“啊,就是那種前后臺通信方式替劈〖娜福”但是在要求詳細(xì)講述它所提出的各個約束,以及如...
    時待吾閱讀 3,410評論 0 19
  • API定義規(guī)范 本規(guī)范設(shè)計基于如下使用場景: 請求頻率不是非常高:如果產(chǎn)品的使用周期內(nèi)請求頻率非常高陨献,建議使用雙通...
    有涯逐無涯閱讀 2,519評論 0 6
  • 學(xué)習(xí)完整課程請移步 互聯(lián)網(wǎng) Java 全棧工程師 本節(jié)視頻 【視頻】解決模塊間的通信問題-RESTful 風(fēng)格的 ...
    擼帝閱讀 1,212評論 1 6
  • 一盒犹、什么是API? API(Application Programming Interface,應(yīng)用程序編程接口)...
    Fairy_妍閱讀 62,544評論 2 42
  • 要說RESTful首先來說說REST – REpresentational State Transfer (表述性...
    趙客縵胡纓v吳鉤霜雪明閱讀 5,505評論 2 121