<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Restful 架構(gòu) API 接口經(jīng)典設(shè)計(jì)誤區(qū)

          共 7253字,需瀏覽 15分鐘

           ·

          2021-05-15 20:18

          背景

          目前微服務(wù)架構(gòu)盛行,在了解了很多的實(shí)際微服務(wù)項(xiàng)目中,發(fā)現(xiàn)很多同事在設(shè)計(jì)業(yè)務(wù) API 接口時(shí),寫法五花八門,現(xiàn)總結(jié)下目前項(xiàng)目上設(shè)計(jì)業(yè)務(wù) API 接口的一些比較經(jīng)典誤區(qū)寫法。

          Restful 架構(gòu)風(fēng)格下,API 接口設(shè)計(jì)經(jīng)典誤區(qū)寫法

          1、查詢某個(gè)對(duì)象接口:GET /app/getImportantApp

          @GetMapping(path = "/getImportantApp")
          public R getImportionApp(@RequestHeader("pid") String pid

          2、查詢列表接口:GET /app/list

          @RequestMapping("/list")
          public R list(String deptId) 

          3、保存對(duì)象接口:POST /app/save

          @PostMapping("/save")
          public R add(CmsAppLicationEntity appLication, String deptId) 

          4、刪除對(duì)象接口:POST /app/delete

          @DeleteMapping("/delete/{applicationId}")
          public R delete(@PathVariable("applicationId") long applicationId) 

          5、更新對(duì)象接口:POST /app/batchUpdate

          @PostMapping("/batchUpdate")
          public R batchUpdate(@RequestBody List<CmsAppLicationEntity> list) 

          是不是感覺很熟悉的代碼,難道寫的不對(duì)?看著挺直觀易懂的。如果采用 Restful 架構(gòu)風(fēng)格,上面這五種寫法當(dāng)然不對(duì),這是對(duì) Restful 架構(gòu)風(fēng)格不了解所致。

          Restful 架構(gòu)風(fēng)格定義

          Restful 是一種軟件架構(gòu)風(fēng)格、設(shè)計(jì)風(fēng)格,而不是標(biāo)準(zhǔn),只是提供了一組設(shè)計(jì)原則和約束條件。它主要用于客戶端和服務(wù)器交互類的軟件。基于這個(gè)風(fēng)格設(shè)計(jì)的軟件可以更簡潔,更有層次,更易于實(shí)現(xiàn)緩存等機(jī)制。

          由于對(duì) Restful 架構(gòu)風(fēng)格理解的不夠透徹,一般會(huì)產(chǎn)生三種爭議的設(shè)計(jì)誤區(qū)。

          1. 誤區(qū)一 請(qǐng)求路徑 URI 是動(dòng)詞,而不是名詞問題
          2. 誤區(qū)二 URI中帶版本號(hào)問題
          3. 誤區(qū)三 URI 中路徑大小寫問題

          誤區(qū)一 請(qǐng)求路徑 URI 是動(dòng)詞,而不是名詞問題

          按照對(duì) Restful 架構(gòu)風(fēng)格理解,每個(gè)業(yè)務(wù)實(shí)體代表一種資源,代表一個(gè)名詞。

          比方說,設(shè)計(jì)產(chǎn)品列表接口時(shí):

          錯(cuò)誤寫法

          /getProductList

          請(qǐng)求路徑 /getProductList 路徑出現(xiàn)動(dòng)詞 get,這種寫法是不對(duì)的。

          推薦寫法

          /products

          另外 URL 出現(xiàn) /addProduct/deleteProduct/updateProduct 等寫法也是不對(duì)的。

          如果某些動(dòng)作是 HTTP 動(dòng)詞表示不了的,你應(yīng)該把該動(dòng)作變成一種資源。

          比方說,我們獲取用戶下的產(chǎn)品列表,錯(cuò)誤接口設(shè)計(jì)是:

          POST /users/1/getProducts

          或者

          POST /users/1/getProductList

          正確的寫法是把動(dòng)詞 getProducts 改成名詞 products

          POST /users/1/products

          誤區(qū)二 URI 中帶版本號(hào)問題

          業(yè)界對(duì) URI 中是否帶版本號(hào)存在三種說法。

          第一種說法是,在請(qǐng)求路徑中加入版本號(hào),比方說:

          POST /products/v1
          GET /users/v1
          POST /orders/v1
          POST /items/v1

          這種說法認(rèn)為,在 URI 中加入版本避免了向后兼容,另外通過過期提示,重定向,文檔等手段也能降低用戶遷移到新的接口上的成本。

          當(dāng)然有人贊成在請(qǐng)求路徑中加入版本號(hào),也有人反對(duì)這種加版本號(hào)的做法,他們認(rèn)為:

          1. 加入版本號(hào)會(huì)讓服務(wù)接口變得混亂,經(jīng)常碰到的情況是,一些低版本的API接口調(diào)用一些高版本的API接口,導(dǎo)致數(shù)據(jù)解析錯(cuò)誤,這無疑加大了用戶遷移的成本。

          2. 版本和資源的概念沒有任何關(guān)系,因此在 URI 中加入版本會(huì)讓用戶混淆。

          還有一種說法是,在路徑中加版本號(hào)是錯(cuò)誤的設(shè)計(jì)方式,在老外寫的 Versioning REST Services 這篇文章指出,你應(yīng)該在請(qǐng)求頭的 Accept 指定你的版本號(hào),而不是請(qǐng)求路徑中。

          例如:

          For example, for versions 1.0, 1.1, and 2.0 of the foo data type as JSON set the Accept/Content-Type header as follows:
          1.0: vnd.example-com.foo+json; version=1.0
          1.1: vnd.example-com.foo+json; version=1.1
          2.0: vnd.example-com.foo+json; version=2.0

          前端 js 在請(qǐng)求頭 Accept 指定 vnd.example-com.foo+json; version=1.1 的版本 version=1.1

          $.ajax({
              beforeSend: function (req) {
                  req.setRequestHeader("Accept""vnd.example-com.foo+json; version=1.1"); 
                  },
              type"GET",
              url: "http://http://www.example.com/foo/12",
              success: function (data) {
                  /* code elided */
              },
              dataType: "json"
          });

          我個(gè)人是比較傾向請(qǐng)求路徑中加版本號(hào)的,因?yàn)槲艺J(rèn)為加版本號(hào)是站在程序角度來考慮新老版本的接口移植問題,特別是現(xiàn)在流行微服務(wù)架構(gòu),業(yè)務(wù)粒度很細(xì)的情況下,接口的升級(jí),原有版本是否保留呢?

          那什么時(shí)候該加版本號(hào)呢?

          如果你開發(fā)的 restful 接口是開放的,你也不知道都有誰調(diào)用過,那么這個(gè)時(shí)候版本號(hào)就是必須的了。以百度地圖接口為例,百度發(fā)布了 restful 風(fēng)格的地圖接口在網(wǎng)上,全國甚至全世界各行各業(yè)都可以調(diào)用這些接口,百度要對(duì)接口進(jìn)行升級(jí),該怎么辦?如果百度直接在原有的url上進(jìn)行升級(jí),會(huì)產(chǎn)生什么樣的結(jié)果呢?不可預(yù)估。程序員:老板,咱們的產(chǎn)品崩潰了!老板:為啥?程序員:百度升級(jí)了接口!哪怕僅僅是多返回了一個(gè)字段,都可能導(dǎo)致調(diào)用者原有的代碼出現(xiàn)問題,畢竟百度無法知道所有人都是怎么解析返回值的。這個(gè)時(shí)候最好的做法就是加版本號(hào),保持原有版本,發(fā)布新的版本,所有問題迎刃而解。老用戶也不用因?yàn)榘俣鹊纳?jí),進(jìn)行代碼的更新,新用戶又能享受最新的接口,完美。

          判斷是否要加版本號(hào)的方法:

          1. 是否明確的知道都有誰調(diào)用了你的接口,并且能通知到,如果能,那可以不加版本號(hào);

          2. restful接口升級(jí)的時(shí)候,原有版本是否保留,如果不保留,可以不加版本號(hào);

          當(dāng)然,加版本號(hào)是有一定技巧的,版本號(hào)應(yīng)該放在一個(gè)功能模塊的后面,甚至一個(gè) url 就應(yīng)該自己獨(dú)立的版本,如 api/user/v2,這樣調(diào)用者就不會(huì)有整套接口都升級(jí)到 v2 的錯(cuò)覺。

          誤區(qū)三 URI 中路徑大小寫問題

          URL 中路徑最好是小寫,不要有駝峰式寫法,比如下面接口錯(cuò)誤寫法

          POST /orderItems/v1/1001

          推薦寫法

          POST /orders/v1/items/1001

          或者

          /order-items/v1/1001

          總結(jié)

          我見過很多采用基于微服務(wù)架構(gòu)編寫的微服務(wù)代碼,大多數(shù)接口看似 restful 風(fēng)格,然而仔細(xì)辨識(shí)才發(fā)現(xiàn),原來是一堆的偽 restful 接口,要么動(dòng)詞名詞不分,要么路徑版本各種混亂。

          實(shí)際上的場景是,restful 風(fēng)格基本上停留在口口相傳上,看起來逼格很高的東西也只能高高供起。大部分的程序員為了趕進(jìn)度,完成 KPI,那還顧得上這種規(guī)范,一直在瘋狂的打碼中。

          附錄1 API 設(shè)計(jì)風(fēng)格基本規(guī)則

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

          不要使用:

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

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

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

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

          /cars 而不是 /car
          /users 而不是 /user
          /products 而不是 /product
          /settings 而部署 /setting
          1. 使用子資源表達(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ī)
          1. 使用 Http 頭聲明序列化格式

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

          Content-Type 定義請(qǐng)求格式
          Accept 定義系列可接受的響應(yīng)格式
          1. 為集合提供過濾 排序 選擇和分頁等功能

          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 集合。

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

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

          Paging 分頁,使用 limitoffset.實(shí)現(xiàn)分頁,缺省 limit=20offset=0

          GET /cars?offset=10&limit=5

          為了將總數(shù)發(fā)給客戶端,使用訂制的 HTTP 頭:X-Total-Count。鏈接到下一頁或上一頁可以在 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",
          1. 版本化你的 API

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

          一般在 Url 后面使用 ?v

          /blog/api/v1
          1. 使用 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)成功擅長
          304 – Not Modified – 客戶端使用緩存數(shù)據(jù)
          400 – Bad Request – 請(qǐng)求無效,需要附加細(xì)節(jié)解釋如 "JSON無效"
          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"
             }
            ]
          }
          1. 允許覆蓋http方法

          一些代理只支持 POST 和 GET 方法, 為了使用這些有限方法支持 RESTful API,需要一種辦法覆蓋 http 原來的方法。使用訂制的 HTTP 頭 X-HTTP-Method-Override 來覆蓋 POST 方法.

          附錄2 HTTP協(xié)議常用的動(dòng)詞說明

          動(dòng)詞描述
          GET查詢列表或者單個(gè)對(duì)象的時(shí)候使用
          POST一般是提交表單或者是查詢參數(shù)比較多的時(shí)候使用
          PUT更新資源的時(shí)候使用
          DELETE刪除資源的時(shí)候使用

          參考

          • https://blog.csdn.net/suo082407128/article/details/60132447
          • http://www.ruanyifeng.com/blog/2011/09/restful.html
          • https://www.informit.com/articles/article.aspx?p=1566460
          • https://blog.csdn.net/qq_27026603/article/details/82012277


          推薦閱讀:

          SpringBoot開發(fā)秘籍 - 集成Graphql Query

          Linux 文件搜索神器 find 實(shí)戰(zhàn)詳解,建議收藏!

          貓撲,涼了!

          搞清楚這 10 幾個(gè)后端面試問題,工作穩(wěn)了!


          關(guān)號(hào)互聯(lián)網(wǎng)全棧架構(gòu)價(jià)

          瀏覽 79
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  五月开心网 | 日韩特级黄色电影 | 99久| 夜夜操夜夜操 | 日韩一区二区三区免费视频 |