RESTful API接口設(shè)計(jì)規(guī)范與最佳實(shí)踐
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
Part1介紹RESTFull 接口設(shè)計(jì)目前廣泛應(yīng)用于各種軟件系統(tǒng)中,特別是前后端分離架構(gòu)的web應(yīng)用。相信各位web應(yīng)用的開發(fā)者對(duì)這個(gè)概念并不陌生,但是我們經(jīng)常會(huì)遇到幾個(gè)這樣的疑惑或者問(wèn)題:
在我們?cè)噲D搞清楚以上幾個(gè)問(wèn)題之前,首先需要讀者了解或者閱讀過(guò)關(guān)于RESTfull的定義,這類定義百度一搜一大把這里就不重復(fù)贅述了。接著是最好你實(shí)踐過(guò)這類風(fēng)格設(shè)計(jì)的接口,如果你心中也同樣有這幾個(gè)問(wèn)題或者疑問(wèn)那就更好了,當(dāng)然最后這兩點(diǎn)要求并不是必須。 如果你已經(jīng)閱讀過(guò)關(guān)于RESTfull的相關(guān)定義,你就會(huì)發(fā)現(xiàn)RESTfull是一種接口設(shè)計(jì)風(fēng)格,它制定了一些原則條件,只要你遵守了,就算是RESTful風(fēng)格的接口設(shè)計(jì)。 那么問(wèn)題就來(lái)了,這里面就存在很多靈活空間了,比如說(shuō)我部分遵守,部分不遵守,可以嗎?可以。或者說(shuō)我在遵守的基礎(chǔ)上,再自定義一些行為,可以嗎?可以。 各種諸如此類的實(shí)踐路線導(dǎo)致了我們很難在開發(fā)生涯中真的看到有兩個(gè)或更多的接口實(shí)現(xiàn)了一模一樣的RESTfull風(fēng)格接口,即便他們的業(yè)務(wù)是一樣的。這是因?yàn)镽ESTfull本身既然是一種設(shè)計(jì)風(fēng)格,那么風(fēng)格發(fā)揮的主動(dòng)權(quán)自然就是在開發(fā)者身上,而且絕大多數(shù)的項(xiàng)目所開發(fā)的API接口都是對(duì)內(nèi)或者有限對(duì)外開放的,所以對(duì)于RESTfull的實(shí)踐是否合格更多取決于內(nèi)部團(tuán)隊(duì)老大的看法。
這里我個(gè)人覺(jué)得有一部分原因是同行襯托,RESTfull基于HTTP協(xié)議,采用json格式的字符串作為傳輸內(nèi)容,相對(duì)于過(guò)去的SOAP協(xié)議,采用XML格式標(biāo)記語(yǔ)言來(lái)說(shuō),RESTfull無(wú)論從開發(fā)成本或者網(wǎng)絡(luò)傳輸來(lái)說(shuō)都顯得輕量太多太多。而前面提到的,關(guān)于實(shí)際開發(fā)出來(lái)的RESTfull接口風(fēng)格迥異的問(wèn)題實(shí)際上并沒(méi)有太糟糕,為什么這么說(shuō)呢?因?yàn)樽钇鸫a的一點(diǎn)是無(wú)論實(shí)際設(shè)計(jì)出來(lái)的接口再奇葩,總歸是基于HTTP協(xié)議和使用JSON字符串來(lái)傳遞數(shù)據(jù),這最起碼保證了我們?cè)谡{(diào)用別人設(shè)計(jì)好的接口的時(shí)候足夠簡(jiǎn)單。 當(dāng)然,能調(diào)用跟實(shí)際交互還有一段很長(zhǎng)的距離,而中間這個(gè)過(guò)程你是否舒適,有一部分就體現(xiàn)在接口細(xì)節(jié)設(shè)計(jì)上了。按照一般的經(jīng)驗(yàn),像這種”標(biāo)準(zhǔn)化“的設(shè)計(jì),我們會(huì)封裝一些基礎(chǔ)方法來(lái)實(shí)現(xiàn)接口的調(diào)用和數(shù)據(jù)接收,但現(xiàn)實(shí)卻是無(wú)法實(shí)現(xiàn)的。因?yàn)镽ESfull接口的具體實(shí)現(xiàn)細(xì)節(jié)上是因人而異的,這就導(dǎo)致了我們封裝的調(diào)用或者解析代碼未必能夠完全復(fù)用,很典型的例子就是我們一開始拋出來(lái)的那幾個(gè)問(wèn)題。 這時(shí)候讀者們肯定想說(shuō),還是想吐槽,是的,我們可以吐槽一個(gè)接口設(shè)計(jì)得很糟心,讓我們調(diào)用起來(lái)很難受,但是我們又不可否認(rèn)他確實(shí)遵守了RESTfull的基本規(guī)定,你可以發(fā)送一個(gè)HTTP請(qǐng)求,通過(guò)JSON來(lái)提交和接收數(shù)據(jù),你完全拿對(duì)方?jīng)]辦法。所以這也就是為什么我們一開始給出的答案是:沒(méi)有對(duì)錯(cuò)。我們可以吐槽一個(gè)接口設(shè)計(jì)得非常糟糕,但是不能說(shuō)這個(gè)接口不是RESTfull接口,但是,我們可以評(píng)判一個(gè)接口是否嚴(yán)格遵循了RESTfull風(fēng)格設(shè)計(jì)以及遵循的程度有多高。 我們可以從開局的幾個(gè)問(wèn)題入手來(lái)嘗試評(píng)判下相應(yīng)的接口設(shè)計(jì)是否很好的遵循了RESTfull風(fēng)格設(shè)計(jì)。 Part2為什么接口只設(shè)計(jì)了GET和POST兩種請(qǐng)求方法類型?
從上面的表格可以看出,不同類型的請(qǐng)求方法有著自己明確的含義,在理想的情況下,我們可以通過(guò)一個(gè)請(qǐng)求類型+請(qǐng)求地址的形式,直觀的看出一個(gè)接口的作用,比如:
這里讀者可以嘗試做一個(gè)閱讀理解。 那么這里問(wèn)題就來(lái)了,既然HTTP的請(qǐng)求方法類型有助于我們理解一個(gè)接口的作用,為什么在有些接口中唯獨(dú)只會(huì)使用GET和POST呢?這里面我覺(jué)得原因有很多,有些可能我也想不到也猜不到,但是我從個(gè)人開發(fā)經(jīng)驗(yàn)上嘗試猜測(cè)一下。
坦白說(shuō),除了查詢請(qǐng)求這種無(wú)可爭(zhēng)議的使用GET之外,其他的全部歸為POST無(wú)疑是一件很方便的事。你不需要花時(shí)間去考慮接口的行為然后決定要定義成什么請(qǐng)求方法類型,反正具體的實(shí)現(xiàn)邏輯都是一樣的,而且POST方法的描述也似乎能涵蓋到其他幾個(gè)類型的請(qǐng)求方法。但這里讀者可能會(huì)說(shuō),在某些場(chǎng)景下會(huì)有歧義,比如說(shuō)我們要調(diào)用一個(gè)接口實(shí)現(xiàn)刪除一個(gè)用戶:
這里我們復(fù)用了前面其中一道閱讀理解題并把類型改成了POST。這里第一眼看上去確實(shí)不能很好的表達(dá)接口的意圖,但是我們有接口文檔呀,我在相應(yīng)的接口名稱中寫清楚再放大字體說(shuō)這個(gè)接口是刪除用戶用的不就完事了?這么一聽好像也有道理。所以綜合看來(lái),細(xì)分各個(gè)方法請(qǐng)求類型似乎變成一件很多余的事,吃力不討好,干脆就GET/POST一把梭了。 說(shuō)到這里,我們?cè)倩剡^(guò)頭來(lái)看看問(wèn)題本身,做錯(cuò)了嗎?沒(méi)有。那嚴(yán)格遵循了RESTfull風(fēng)格設(shè)計(jì)了嗎,那倒是并沒(méi)有。
遵循 RESTfull
不遵循RESTfull
從這里的示例可以看出,在不遵循RESTfull風(fēng)格設(shè)計(jì)的情況下我們難免需要在接口URL地址中增加一些描述性的單詞,這會(huì)導(dǎo)致路由接口地址變得很冗長(zhǎng)和不夠優(yōu)雅,當(dāng)然如果你覺(jué)得這不是什么問(wèn)題那也是沒(méi)錯(cuò)的,對(duì),你沒(méi)錯(cuò)。
Part3為什么接口是否請(qǐng)求成功,HTTP狀態(tài)碼永遠(yuǎn)只會(huì)是200?
從上面表格可以看出,HTTP碼是用于標(biāo)識(shí)本次請(qǐng)求響應(yīng)的結(jié)果狀態(tài),通過(guò)HTTP狀態(tài)我們可以直觀的判斷出本請(qǐng)求是不是成功的,但是為什么有些接口設(shè)計(jì)的情況是無(wú)論成功與否都只會(huì)返回200的狀態(tài)碼呢?
首先假設(shè)我們把所有請(qǐng)求響應(yīng)的HTTP狀態(tài)碼都標(biāo)識(shí)為200,那么我們必然需要在響應(yīng)內(nèi)容中增加一些字段來(lái)描述本次錯(cuò)誤,例如:
這里大家可能會(huì)覺(jué)得,我們已經(jīng)有code和message字段來(lái)描述本次請(qǐng)求的錯(cuò)誤了,完全不需要HTTP狀態(tài)碼。這里乍一看是沒(méi)有問(wèn)題的,前端也能在統(tǒng)一異常處理的層面很好的捕獲異常。 但是,當(dāng)你的系統(tǒng)到了一定的規(guī)模(這個(gè)很容易達(dá)到,并不要求需要多大的規(guī)模體量,只要不是demo項(xiàng)目),你的錯(cuò)誤類型就會(huì)有很多種,往往我們的錯(cuò)誤碼清單會(huì)很長(zhǎng),當(dāng)然這對(duì)于后端開發(fā)來(lái)說(shuō)不是啥問(wèn)題,因?yàn)檫@個(gè)信息其實(shí)是給前端開發(fā)者處理的,但是前端開發(fā)者在處理這些錯(cuò)誤的時(shí)候就難受了。 難受在哪?假設(shè)我們現(xiàn)在有10個(gè)關(guān)于賬戶異常的錯(cuò)誤碼,10個(gè)關(guān)于業(yè)務(wù)A的錯(cuò)誤碼,10個(gè)關(guān)于業(yè)務(wù)B的錯(cuò)誤碼,一共30個(gè)。這里面有個(gè)業(yè)務(wù)需求,就是某些特定的錯(cuò)誤碼需要前端做出特定的行為,比如說(shuō)跳轉(zhuǎn)到指定頁(yè)面,或者強(qiáng)制退出啥等等。那么這時(shí)候前端在統(tǒng)一異常處理的時(shí)候咋做?那就是各種 看起來(lái)似乎也問(wèn)題不大嘛,是的,接著我們需求變了,和原來(lái)不一樣了,原來(lái)的分支判斷條件可能不適用了,錯(cuò)誤碼改了,含義不一樣了,或者又增加了30個(gè)新的錯(cuò)誤碼,那么這時(shí)候前端開發(fā)者就炸了。
比如說(shuō)給后端傳遞了錯(cuò)誤的參數(shù),這種一般后端在校驗(yàn)不通過(guò)的時(shí)候,會(huì)返回的HTTP狀態(tài)碼是400。這類提示信息是需要把具體錯(cuò)誤信息展示給用戶作為警告提示的,那么前端開發(fā)者在統(tǒng)一異常處理的時(shí)候,只需要判斷HTTP狀態(tài)碼是不是400,是的話直接把具體內(nèi)容以各種彈出提示的形式展示即可,不用關(guān)心具體的錯(cuò)誤碼又是什么(需要特殊處理的除外)。還有一種是401和**403 **HTTP狀態(tài)碼的錯(cuò)誤,這兩種都是跟權(quán)限有關(guān)的錯(cuò)誤,前端開發(fā)者在做統(tǒng)一異常處理的時(shí)候也可以進(jìn)行針對(duì)性的統(tǒng)一捕獲處理。
相對(duì)于單純依靠錯(cuò)誤碼,HTTP狀態(tài)碼+錯(cuò)誤碼的方式讓前端開發(fā)者更容易實(shí)現(xiàn)封裝和統(tǒng)一處理,前端開發(fā)者根據(jù)HTTP狀態(tài)碼定義不同的響應(yīng)處理,可以大大減少開發(fā)工程量和降低溝通成本。但是這里讀者們可能會(huì)說(shuō),我們可以把錯(cuò)誤碼按范圍劃分,實(shí)現(xiàn)比如1~99是代表XX類型錯(cuò)誤,100~199是XX類型錯(cuò)誤。這個(gè)確實(shí)可以,但是這等于是換了條路開倒車,其實(shí)還是會(huì)有一開始的提到的痛點(diǎn)問(wèn)題出現(xiàn)。而且錯(cuò)誤碼因?yàn)槭菆F(tuán)隊(duì)定義的,如果維護(hù)不善會(huì)導(dǎo)致各種前后端開發(fā)者信息不同步的問(wèn)題,既然通過(guò)HTTP狀態(tài)碼的定義就能解決大部分問(wèn)題了為什么不用呢? 最后總結(jié)一下這個(gè)問(wèn)題就是,強(qiáng)烈建議嚴(yán)格按照HTTP狀態(tài)碼的定義區(qū)分接口響應(yīng)的HTTP狀態(tài)碼,錯(cuò)誤碼作為一種細(xì)分的補(bǔ)充。 Part4HTTP狀態(tài)碼不存在,返回 200 還是 404 ?問(wèn)題: 當(dāng)一個(gè)查詢的結(jié)果為空的時(shí)候,為什么有的接口設(shè)計(jì)會(huì)返回異常(HTTP狀態(tài)碼404或其他),有的則是會(huì)返回請(qǐng)求成功(HTTPS狀態(tài)碼200),但是返回結(jié)果是空數(shù)組或者null等表示結(jié)果為空的標(biāo)識(shí)? 解析:這個(gè)問(wèn)題情況有點(diǎn)特殊,理論上來(lái)說(shuō),當(dāng)我們查詢了資源然后結(jié)果是不存在的時(shí)候,這個(gè)時(shí)候用404的HTTP狀態(tài)碼來(lái)標(biāo)識(shí)本次請(qǐng)求的響應(yīng)狀態(tài)是一點(diǎn)問(wèn)題都沒(méi)有的,也是非常規(guī)范的做法。但是這是建立在業(yè)務(wù)場(chǎng)景規(guī)定,查詢結(jié)果為空的時(shí)候?qū)儆诋惓5那疤嵘稀?/p> 1返回HTTP狀態(tài)碼 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |