從“上帝”視角看後端接口如何設計

這裏先說說“上帝”是什麼?上帝,是移動端,pc端,h5端的統稱,爲什麼這麼說呢,接口設計的最終目標,是讓用戶可以正常使用軟硬件提供的服務。用戶使用不同的端來訪問接口,從而與後端發生關聯關係,進而使用相關的服務。

而這些端的開發者,他們將界面與接口進行有效的結合形成一個個有機體,不同的有機體組合形成一套系統,他們使用接口,他們是顧客(自家的接口免費用,別人的接口限制或者付費用),而顧客是什麼?是上帝,因此,作爲“上帝”之一的移動端,有必要聊聊接口設計的東西,儘管有可能以下內容會對後端開發人員造成不適感,也要勇敢說出來。另外,也算是對接口設計思考與認知的總結。歡迎各位看官小夥伴提出一些看法,一起進步。

接口設計規範

基本性

基本性是指,接口地址符合一般性URL所具有的要素。

1.請求path
栗子

這裏,以獲取商品詳情信息,get請求,如下:
http://www.xxx.com/Goods/getGoodsInfo?id=10025

http:是網絡協議部分,該部分規定數據交互遵守的統一標準。
     現實中,可以是https,還可以是ftp或者rtmp等
xxx.com:是域名部分,該部分域名訪問時,需要進行地址映射,域名->ip地址
     現實中,既可以是域名,也可以是ip地址(尤其調試階段,各種ip地址,畢竟後端人員多,各個對接)
path:Goods/getGoodsInfo?id=10025(斜體加粗部分)
Goods:是後端功能模塊,不同的功能模塊,這部分對應內容有所不同。如,User信息模塊,/user/getUserInfo
getGoodsInfo:是模塊功能中某一具體功能對應的action(前端)或者method(後端),這裏指獲取商品信息的方法
    ?id=10025:?是一個特殊的分隔符,用於獲取其後攜帶的參數,id爲參數

在真實項目中,形似上述接口可能有很多,大家在使用這些接口時也習以爲常,畢竟接口能正常走通。不過,不知道小夥伴們有沒有發現不太合理的地方?暫且先留個問題,繼續往下看

path設計原則

1.見名知意 好的path設計,使用者(開發人員或者測試人員)看到接口時,就可以很清楚的瞭解接口對應的功能。上述的栗子,在一定程度反映了對應的功能。以常見一些功能爲慄,如下:

method Path 含義 栗子 具體說明
GET getXxxx 查找或者查詢 getUserInfo 獲取用戶信息
POST addXxxx 提交或者增加 addOrder 增加新訂單
POST modifyXxxx 修改或者更新 modifyUserInfo 修改用戶信息
POST deleteXxxx 刪除 deleteAddress 刪除地址

這樣可以減少不必要的溝通成本,記得,該溝通時一定要溝通,畢竟不是所有的設計都是那麼規範。你走過的路不一定是別人的套路,有可能是血路,用同感嗎?

總結,一句話,當看到接口時,我就知道對應的是什麼功能

2.個性參數

個性,對於人來說,不同的人具有不同的性格特點。個性參數,對於接口而言,是不同的網絡請求,使用到不同的參數。

栗子
getOrderList?orderId=1022001
getMemberInfo?memeberId=135xxxxxxxx

modifyUserInfo?
個性參數設計原則

1.見名知意 比如,oderId,goodsId。一定不要只寫id,這種參數,尤其是同一個接口,涉及到多個id相類似參數。坦白說,對接接口時可能是知道具體含義,但後期維護時不一定還記得。
很有必要在id的前面加上一定的前綴
2.必傳,參數設定必須要有的信息,有無默認初始,參數類型規定,統一String
3.選傳,參數可有可無,有無默認初始,參數類型規定,統一String
4.註釋,要清楚,每個參數是幹什麼用的,有具體的描述信息,無論是正常開發,還是後期維護,還是新同事接觸項目,都是非常有幫助的

3.公共參數

所謂公共參數,每一個網絡請求都會使用到的參數,就是公共參數或者通用參數。這些參數是請求必須要有的,這些參數具有描述性的特點

栗子
參數名稱 具體說明
userToken 用戶認證,用戶登錄成功後獲取,後續請求需要攜帶
netType 網絡類型(2G、3G、4G,WIFI)
osType 手機系統版本
osDesc 機型信息
screen 分辨率信息,獲取匹配的圖片
curVersion 當前版本信息
visitFrom 訪問來源,如,pc端,h5,android、ios
channel 訪問渠道,不同的應用市場

說明一點:現實項目中公共參數包括但不限於這些,因需求而有所不同

設計原則

公共參數設計,可以從身份認證,數據統計,問題定位,用戶體驗等角度進行參數設計

身份認證:如,攜帶token進行認證等
數據統計:如,當前使用app版本,從而控制版本。當前訪問app下載所屬渠道等
問題定位:如,手機系統版本,手機類型,手機分辨率等

1.必傳,參數設定必須要有的信息,有無默認初始,參數類型規定,統一String
2.選傳,參數可有可無,有無默認初始,參數類型規定,統一String
3.註釋,要清楚,每個參數是幹什麼用的,有具體的描述信息。

4.響應數據

響應數據,是指客戶端向服務器發送請求,正常情況下,服務器對於請求有一個具體的響應反饋,先來看下三個栗子

栗子1

針對非查詢的,某種操作,比如刪除,響應數據

{
    repCode:0000,
    repMsg: "刪除成功",
    repTime: "20180410162022"
}
栗子2

針對查詢的,比如查詢某用戶具體信息,響應數據(Object)

{
    repCode:0000,
    repMsg: "請求成功",
    repTime: "20180410163020",
    data:{
        userInfo:{
            userName: "小明",
            userNick: "無黃瓜不雞蛋",
            userHeader: "http://www.xxxx.com/users/iamges/xxxx.jpg"
        //.......
        }
    }
}
栗子3

針對查詢的,比如查詢某用戶的好友列表,響應數據(Array)

    repCode:0000,
    repMsg: "請求成功",
    repTime: "20180410163020",
    data:{
        content:[
            {
                userName: "小花",
                userNick: "綠洲一片紅",
                userHeader: "http://www.xxxx.com/users/iamges/xxxx.jpg"
                //.......
            },
            {
                userName: "小白",
                userNick: "愛喝旺仔的饅頭",
                userHeader: "http://www.xxxx.com/users/iamges/xxxx.jpg"
                //.......
            }
            //xxxxx更多
        ]
    }

通過以上的栗子,可以看出響應數據有共同之處

參數名稱 參數含義 具體說明
repCode 響應狀態碼 狀態碼一般有0000代表請求響應成功,非0000代表失敗。或者其他如200代表響應成功,非200代表失敗。具體看後臺設定
repMsg 響應狀態值 1.當前操作的具體文字說明,如查詢成功,刪除成功,刪除失敗。2.不同的repCode對應不同的repMsg
repTime 服務端響應時間 一般會同步時間使用
data 響應數據內容 服務端返回核心數據部分
說明:
repCode狀態碼,除請求成功以外的各種狀態,如果可以細分,儘可能細分,
repMsg狀態描述,在repCode細分情況下,客戶端在請求失敗時,一方面,可以給予用戶很好的反饋,告知用戶當前操作出現問題的原因。另一方面,可以幫助開發很好的定位問題原因。總之,返回repMsg不要太任性,出來混遲早要還的哈
響應數據設計規則

1.響應的數據,其結構參照上表進行設計,具體參考栗子
2.響應的狀態描述(repMsg)儘可能明確,不要太隨意
3.針對json的結構,保持數據良好的閱讀性以及對bean類的複用。不同的字段儘可能放到不同的對象中
4.所有的數據儘可能以單個或者多個Object形式返回。最好不要是很多個數組,比如,userName一個數組,userAge一個數組,客戶端需要循環根據索引取值後。自己封裝成Object
5.列表形式的數據,需要返回下一頁頁數,總頁數

這裏,有一個點,無論是請求還是響應數據,具體到每個Object內的參數,其類型最好統一爲String,尤其現在大家會使用第三方的數據解析工具,比如Gson,那麼,在遇到下面情況時,
Int類型:

拋出NumberFormatException(本來需要90,結果返回的是90.8)
拋出IllegalStateException(本來需要的是20,結果返回的是"20")

Boolean類型:

拋出IllegalStateException(本來需要的是true,結果返回的是"true"或者1)

Float類型:

拋出NumberFormatException(本來需要90.0,結果返回的是"90.0"或者abc)

鑑於上述情況,最好將所有Object內參數類型,接收參數統一爲String
改爲String後,有以下幾點優點

1.容錯能力增強,降低解析失敗導致異常機率
2.省略掉拼接“”或者String.valueOf()
3.避免掉TextView中setText找不到資源問題

有以下缺點:

1.需要對String進行一層進行類型轉換,轉換爲boolean或者float類型
2.對String要進行null處理,避免空指針,或者需要後臺配合爲null時返回""

輕量性

1.客戶端app不應包含業務邏輯的處理,只負責展示

有同學會說,相比服務器,客戶端沒有什麼複雜邏輯啊,客戶端一樣可以進行簡單邏輯。這裏,舉個栗子,如下:

訂單列表中,訂單具有不同的狀態,客戶端需要根據狀態值不同展示不同狀態描述。

先看客戶端處理,一般需要根據服務器返回的狀態code或者state判斷處理後,展示不同文字(有判斷邏輯)
再看看服務器端,根據狀態code或者state判斷處理後,返回不同文字給客戶端,客戶端直接取出後展示(沒有判斷處理邏輯)

比較上述兩種處理方式,會發現當需求變更時,客戶端或者服務器會變更處理邏輯,但是客戶端有可能需要發佈新版本,搞不好,安卓段,ios端,h5端都要發佈版本。而服務器更改後,各個端可以即時同步,相比之下,客戶端維護端成本高,發佈版本代價也很高

建議這種只是描述性的文字展示(訂單狀態說明或者某個操作說明或者錢包總額,提現說明,版本更新等信息)儘可能的由後臺進行返回
當然,客戶端根據不同狀態跳轉不同界面的邏輯還是要有的

2.客戶端儘可能不做金額計算業務

這裏,舉個栗子,如下:

結算賬單頁面,客戶端的選擇項原價多少,使用優惠券多少,最終付款多少等

一般情況下,客戶端會將上述項,傳遞給服務器,服務器去查詢相關信息重新再做結算,爲什麼重新計算呢?避免客戶端計算結果有偏差。客戶端計算後直接傳遞支付金額給服務器看似很方便,但是風險很高,那兒怕一分錢,也有可能產生糾紛或者丟掉一個用戶。這種情況下,客戶端負責展示就好,涉及到金額的最好在服務器處理

安全性

1.請求,校驗接口訪問者合法性

證書校驗,Header校驗,token校驗等

2.請求,涉及用戶帳號、密碼信息加密

一般出現在登錄接口時,需要對用戶帳號、密碼進行加密傳遞,避免被攔截獲取明文

3.請求,涉及金額從服務器重新覈算校驗
4.響應,涉及用戶敏感信息加密或者隱藏

如,手機號,身份證,郵箱,支付帳號,銀行卡號,地址等,在客戶端展示時,將部分數據以“*”代替

拓展性

1.從響應數據結構來考慮,原本單個參數,是否有必要以對象方式返回,單個對象,是否考慮以list方式返回

兼容性

原有版本與新版本使用同一接口,新版本需要修改接口,尤其是線上還在使用情況下,原則上,儘可能不去做參數刪除,優先考慮新增參數
如果需要改動的參數很多,可以考慮使用新接口

其他優化

1.同一界面,是否可以將多個接口合併

考慮到資源,電量,頻繁的創建網絡請求等,考慮是否合併

2.不同界面,是否可以將多個接口合併

有時某個接口只是單純的獲取一項信息,而該信息可能在很多地方使用到,這時考慮是否在某個接口統一返回放到緩存中

3.減少網絡請求

接口獲取數據,根據本地md5值與服務器md5值改變,來判斷是否有更新,沒有則取緩存,有則更換最新。首次md5爲null

4.接口參數名精簡,做到見名知意

儘可能使用少量單詞書寫參數

5.無用參數清理

這個說起來很容易,操作起來不見得。上面說過,儘可能不去做刪除參數操作,所以,凸顯出接口文檔的重要性,每個接口,每個參數都有相應的記錄說明,無用參數清理就變得簡單些

6.列表帶圖時,顯示小圖,詳情,顯示大圖

設計接口時需要考慮到圖片顯示問題,畢竟圖片展示是耗流量的大戶,即便流量不是問題,大圖展示時比較耗時,所以,流量消耗,時間消耗,是需要考慮的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章