狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

RESTful API接口設計規范與最佳實踐

admin
2023年11月29日 14:13 本文熱度 692

Part1介紹

RESTFull 接口設計目前廣泛應用于各種軟件系統中,特別是前后端分離架構的web應用。相信各位web應用的開發者對這個概念并不陌生,但是我們經常會遇到幾個這樣的疑惑或者問題:

  1. 為什么這個接口只設計了GET和POST兩種請求類型?
  2. 為什么這個接口無論是否請求成功,HTTP狀態碼永遠只會是200?
  3. 當一個查詢的結果為空的時候,為什么有的接口設計會返回異常(HTTP狀態碼404或其他),有的則是會返回請求成功(HTTPS狀態碼200),但是返回結果是空數組或者null等表示結果為空的標識?

以上這幾個問題,哪些是對的哪些是錯的呢?答案是:沒有對錯

在我們試圖搞清楚以上幾個問題之前,首先需要讀者了解或者閱讀過關于RESTfull的定義,這類定義百度一搜一大把這里就不重復贅述了。接著是最好你實踐過這類風格設計的接口,如果你心中也同樣有這幾個問題或者疑問那就更好了,當然最后這兩點要求并不是必須。

如果你已經閱讀過關于RESTfull的相關定義,你就會發現RESTfull是一種接口設計風格,它制定了一些原則條件,只要你遵守了,就算是RESTful風格的接口設計。

那么問題就來了,這里面就存在很多靈活空間了,比如說我部分遵守,部分不遵守,可以嗎?可以?;蛘哒f我在遵守的基礎上,再自定義一些行為,可以嗎?可以。

各種諸如此類的實踐路線導致了我們很難在開發生涯中真的看到有兩個或更多的接口實現了一模一樣的RESTfull風格接口,即便他們的業務是一樣的。這是因為RESTfull本身既然是一種設計風格,那么風格發揮的主動權自然就是在開發者身上,而且絕大多數的項目所開發的API接口都是對內或者有限對外開放的,所以對于RESTfull的實踐是否合格更多取決于內部團隊老大的看法。

說到這里讀者們可能會覺得,既然如此那這個真是太糟糕了,完全做不到統一,你完全想象不到別人設計出什么魔幻風格的RESTfull接口,為什么RESTfull依然能成為主流的接口設計風格呢?

這里我個人覺得有一部分原因是同行襯托,RESTfull基于HTTP協議,采用json格式的字符串作為傳輸內容,相對于過去的SOAP協議,采用XML格式標記語言來說,RESTfull無論從開發成本或者網絡傳輸來說都顯得輕量太多太多。而前面提到的,關于實際開發出來的RESTfull接口風格迥異的問題實際上并沒有太糟糕,為什么這么說呢?因為最起碼的一點是無論實際設計出來的接口再奇葩,總歸是基于HTTP協議和使用JSON字符串來傳遞數據,這最起碼保證了我們在調用別人設計好的接口的時候足夠簡單。

當然,能調用跟實際交互還有一段很長的距離,而中間這個過程你是否舒適,有一部分就體現在接口細節設計上了。按照一般的經驗,像這種”標準化“的設計,我們會封裝一些基礎方法來實現接口的調用和數據接收,但現實卻是無法實現的。因為RESfull接口的具體實現細節上是因人而異的,這就導致了我們封裝的調用或者解析代碼未必能夠完全復用,很典型的例子就是我們一開始拋出來的那幾個問題。

這時候讀者們肯定想說,還是想吐槽,是的,我們可以吐槽一個接口設計得很糟心,讓我們調用起來很難受,但是我們又不可否認他確實遵守了RESTfull的基本規定,你可以發送一個HTTP請求,通過JSON來提交和接收數據,你完全拿對方沒辦法。所以這也就是為什么我們一開始給出的答案是:沒有對錯。我們可以吐槽一個接口設計得非常糟糕,但是不能說這個接口不是RESTfull接口,但是,我們可以評判一個接口是否嚴格遵循了RESTfull風格設計以及遵循的程度有多高。

我們可以從開局的幾個問題入手來嘗試評判下相應的接口設計是否很好的遵循了RESTfull風格設計。

Part2為什么接口只設計了GET和POST兩種請求方法類型?

解析:HTTP協常用的請求方法類型有GETPOST、PUT、PATCHdelete,其中毫無疑問GETPOST是最最最常用的,而且每個請求方法類型都有各自的描述:

序號類型描述
1GET請求指定的頁面信息,并返回實體主體
2POST向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST 請求可能會導致新的資源的建立和/或已有資源的修改
3PUT從客戶端向服務器傳送的數據取代指定的文檔的內容
4PATCH是對 PUT 方法的補充,用來對已知資源進行局部更新
5delete請求服務器刪除指定的頁面

從上面的表格可以看出,不同類型的請求方法有著自己明確的含義,在理想的情況下,我們可以通過一個請求類型+請求地址的形式,直觀的看出一個接口的作用,比如:

// 猜猜阿克蘇我想干嘛
GET https://tinywan.com/users

delete  https://tinywan.com/users/69

這里讀者可以嘗試做一個閱讀理解。

那么這里問題就來了,既然HTTP的請求方法類型有助于我們理解一個接口的作用,為什么在有些接口中唯獨只會使用GET和POST呢?這里面我覺得原因有很多,有些可能我也想不到也猜不到,但是我從個人開發經驗上嘗試猜測一下。

原因我覺得可能是一是懶,二是覺得沒必要,三是根本不會設計。

坦白說,除了查詢請求這種無可爭議的使用GET之外,其他的全部歸為POST無疑是一件很方便的事。你不需要花時間去考慮接口的行為然后決定要定義成什么請求方法類型,反正具體的實現邏輯都是一樣的,而且POST方法的描述也似乎能涵蓋到其他幾個類型的請求方法。但這里讀者可能會說,在某些場景下會有歧義,比如說我們要調用一個接口實現刪除一個用戶:

  // 猜猜我想干嘛
  POST https://tinywan.com/users/69

這里我們復用了前面其中一道閱讀理解題并把類型改成了POST。這里第一眼看上去確實不能很好的表達接口的意圖,但是我們有接口文檔呀,我在相應的接口名稱中寫清楚再放大字體說這個接口是刪除用戶用的不就完事了?這么一聽好像也有道理。所以綜合看來,細分各個方法請求類型似乎變成一件很多余的事,吃力不討好,干脆就GET/POST一把梭了。

說到這里,我們再回過頭來看看問題本身,做錯了嗎?沒有。那嚴格遵循了RESTfull風格設計了嗎,那倒是并沒有。

RESTfull是基于HTTP協議的,HTTP協議里面清清楚楚明明白白提供了這些方法類型,那么從嚴謹的角度上來說,我們確實是需要清楚的定義好每個請求的類型是什么。這不僅是有利于提高接口語義化,其實對接口地址定義也有些好處,比如說我們要定義一套對用戶進行CRUD的接口。

遵循 RESTfull

// 遵循RESTfull
GET     https://tinywan.com/users

GET     https://tinywan.com/users/1

POST    https://tinywan.com/users
Body:   "{"username":"Tinywan","password":123446}"

PUT     https://tinywan.com/users/1
Body:   "{"username":"阿克蘇","password":wt@123465}"

PATCH   https://tinywan.com/users/69
Body:   "{"password":999999}"

delete  https://tinywan.com/users/1

不遵循RESTfull

GET     https://tinywan.com/users

GET     https://tinywan.com/users/1

POST    https://tinywan.com/users
Body:   "{"username":"Tinywan","password":123446}"

POST    https://tinywan.com/put/users/1
Body:   "{"username":"阿克蘇","password":wt@123465}"

POST    https://tinywan.com/patch/user/69
Body:   "{"password":999999}"

POST    https://tinywan.com/delete/user/1

注意:在不遵循RESTfull風格的情況下,因為除了GET以外都是POST類型請求,我們需要為相同POST請求的接口定義不同的路由地址,這里示例中的路由地址只是為了體現這一點,真實開發場景中如何命名各有各發揮。

從這里的示例可以看出,在不遵循RESTfull風格設計的情況下我們難免需要在接口URL地址中增加一些描述性的單詞,這會導致路由接口地址變得很冗長和不夠優雅,當然如果你覺得這不是什么問題那也是沒錯的,對,你沒錯。

最后總結一下這個問題就是,你可以不遵循RESTfull風格設計里面關于對請求方法類型的區分定義,但需要在路由地址上花心思,那么在真實開發場景中,我們該如何選擇呢?我的建議是如果你能做主,而且覺得有必要,就嚴格遵循,反之,領導說就啥吧。

Part3為什么接口是否請求成功,HTTP狀態碼永遠只會是200?

解析:常見的HTTP狀態碼有如下幾種:

狀態碼英文名稱描述
200OK請求成功。一般用于GET與POST請求
201created已創建。成功請求并創建了新的資源
400Bad Request業務錯誤,語義有誤,當前請求無法被服務器理解
401Unauthorized認證失敗,當前請求需要用戶驗證
403Forbidden無權限調用接口,服務器已經理解請求,但是拒絕執行它
404Not Found服務器無法根據客戶端的請求找到資源(網頁)。通過此代碼,網站設計人員可設置"您所請求的資源無法找到"的個性頁面
429Has Many請求次數超過限定次數(目前限定一分鐘6次請求)
500Internal Server Error服務器內部錯誤,無法完成請求

從上面表格可以看出,HTTP碼是用于標識本次請求響應的結果狀態,通過HTTP狀態我們可以直觀的判斷出本請求是不是成功的,但是為什么有些接口設計的情況是無論成功與否都只會返回200的狀態碼呢?

這里的原因和第1點的問題大致相同,就是懶和覺得沒必要。但相對于明確方法請求類型來說,明確接口響應的HTTP狀態碼卻是大有意義。

首先假設我們把所有請求響應的HTTP狀態碼都標識為200,那么我們必然需要在響應內容中增加一些字段來描述本次錯誤,例如:

// 200
{
  // 定義一個錯誤碼
  "code": 1024,
  // 錯誤碼對應的錯誤信息描述
  "message""密碼不正確"
}

這里大家可能會覺得,我們已經有code和message字段來描述本次請求的錯誤了,完全不需要HTTP狀態碼。這里乍一看是沒有問題的,前端也能在統一異常處理的層面很好的捕獲異常。

但是,當你的系統到了一定的規模(這個很容易達到,并不要求需要多大的規模體量,只要不是demo項目),你的錯誤類型就會有很多種,往往我們的錯誤碼清單會很長,當然這對于后端開發來說不是啥問題,因為這個信息其實是給前端開發者處理的,但是前端開發者在處理這些錯誤的時候就難受了。

難受在哪?假設我們現在有10個關于賬戶異常的錯誤碼,10個關于業務A的錯誤碼,10個關于業務B的錯誤碼,一共30個。這里面有個業務需求,就是某些特定的錯誤碼需要前端做出特定的行為,比如說跳轉到指定頁面,或者強制退出啥等等。那么這時候前端在統一異常處理的時候咋做?那就是各種if/elseswitch判斷。

看起來似乎也問題不大嘛,是的,接著我們需求變了,和原來不一樣了,原來的分支判斷條件可能不適用了,錯誤碼改了,含義不一樣了,或者又增加了30個新的錯誤碼,那么這時候前端開發者就炸了。

所以從這里可以看出,單純依靠錯誤碼來實現前端統一異常處理依然會存在重復編碼問題,那么如果我們嚴格遵循RESTfull風格設計的話,增加HTTP狀態碼的區分定義,同時保留原來的錯誤響應信息結果會是如何?這時候前端開發者在做統一異常處理的時候,先按狀態碼做一層大范圍的分支處理,再有針對性的對這個狀態碼類型下的某些錯誤碼做特殊處理即可。

這兩種方式的區別在于,通過HTTP狀態碼相當于給錯誤碼做了一個歸類,這也符合真實開發場景的異常處理情況。多數情況下前端在對異常做統一處理的時候,同一類型的異常往往后續的處理行為是一致的。

比如說給后端傳遞了錯誤的參數,這種一般后端在校驗不通過的時候,會返回的HTTP狀態碼是400。這類提示信息是需要把具體錯誤信息展示給用戶作為警告提示的,那么前端開發者在統一異常處理的時候,只需要判斷HTTP狀態碼是不是400,是的話直接把具體內容以各種彈出提示的形式展示即可,不用關心具體的錯誤碼又是什么(需要特殊處理的除外)。還有一種是401和**403 **HTTP狀態碼的錯誤,這兩種都是跟權限有關的錯誤,前端開發者在做統一異常處理的時候也可以進行針對性的統一捕獲處理。

從上面舉的一些例子可以看出,相同的HTTP狀態碼,前端的處理行為往往是一致的,但錯誤碼未必。

相對于單純依靠錯誤碼,HTTP狀態碼+錯誤碼的方式讓前端開發者更容易實現封裝和統一處理,前端開發者根據HTTP狀態碼定義不同的響應處理,可以大大減少開發工程量和降低溝通成本。但是這里讀者們可能會說,我們可以把錯誤碼按范圍劃分,實現比如1~99是代表XX類型錯誤,100~199是XX類型錯誤。這個確實可以,但是這等于是換了條路開倒車,其實還是會有一開始的提到的痛點問題出現。而且錯誤碼因為是團隊定義的,如果維護不善會導致各種前后端開發者信息不同步的問題,既然通過HTTP狀態碼的定義就能解決大部分問題了為什么不用呢?

最后總結一下這個問題就是,強烈建議嚴格按照HTTP狀態碼的定義區分接口響應的HTTP狀態碼,錯誤碼作為一種細分的補充。

Part4HTTP狀態碼不存在,返回 200 還是 404 ?

問題: 當一個查詢的結果為空的時候,為什么有的接口設計會返回異常(HTTP狀態碼404或其他),有的則是會返回請求成功(HTTPS狀態碼200),但是返回結果是空數組或者null等表示結果為空的標識?

解析:這個問題情況有點特殊,理論上來說,當我們查詢了資源然后結果是不存在的時候,這個時候用404的HTTP狀態碼來標識本次請求的響應狀態是一點問題都沒有的,也是非常規范的做法。但是這是建立在業務場景規定,查詢結果為空的時候屬于異常的前提上。

1返回HTTP狀態碼 200

當我們查詢一個資源但是結果為空,到底要不要把本次請求視為一個404的異常是取決于業務場景。如果說業務場景認為”空“是允許的,那么就不應該讓本次響應是一個404的HTTP狀態碼,因為有些業務場景下,“空”也是有它的業務含義的

比如我們要查詢一個月內連續登陸10天的用戶列表,結果是沒有用戶滿足這個條件,那么我返回的結果自然是空的,并不能視為一個異常,這時候返回一個200的HTTP狀態碼,然后在響應結果里面明確結果是空的才是正確的做法。

2返回HTTP狀態碼 404

那么什么場景下”空“是不允許的呢?比如說我們要修改指定的某個用戶的個人信息,那么通常情況下我們后端的處理邏輯是這樣的:查詢這個用戶是否存在,如果存在則進行更新操作,如果不存在,拋出一個異常提示要修改的用戶不存在。在這種場景下,這個異常就會是一個404異常,我們嘗試修改一個并不存在的用戶。

最后總結一下這個問題,當請求的結果為空時,是不是屬于異常要考慮業務場景,并且這個劃分定義也是很有必要的,可以避免潛在的業務理解偏差導致的程序執行邏輯問題,因為如果是一個異常,那么會更早的被前端在統一異常處理里面的捕獲并處理,有利于前、后端開發人員開發出更健壯的系統。


該文章在 2023/12/7 11:37:56 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved