XX公司APP介面設計規範v1
APP介面設計規範v1
張遂程 2018年02月06日16:15:03
前言
沒有最優的方案,只有最適合的方案,本文指出對APP介面設計的一些規範與大家分享和共勉,涉及到APP介面設計規範v1.0,設計案例的分享,和一些PHP編碼的要求,目的在於開發出效能優異,結構清晰,維護便捷,安全,和高拓展性的介面。如果有說得不正確的地方,也請大家指出。
經驗學習
在專案中,要做到融會貫通,首先就應該做到多學習,學習大廠的經驗和總結,如果能避免到別家遇到的坑,那麼就最好了,如果避免不到,那麼也能做到心中運籌帷幄。程式開發中有句很流行話就是,”不要重複造輪子”,要”時刻明確自己是搬磚民工,不是燒磚的窯”。
新浪微博 open api
{
"users": [
{
"id": 1404376560,
"screen_name": "zaku",
"name": "zaku",
"province": "11",
"city": "5",
"location": "北京 朝陽區",
"description": "人生五十年,乃如夢如幻;有生斯有死,壯士復何憾。",
"url ": "http://blog.sina.com.cn/zaku",
"profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1",
"domain": "zaku",
"gender": "m",
"followers_count": 1204,
"friends_count": 447,
"statuses_count": 2908,
"favourites_count": 0,
"created_at ": "Fri Aug 28 00:00:00 +0800 2009",
"following": false,
"allow_all_act_msg": false,
"remark": "",
"geo_enabled": true,
"verified": false,
"status": {
"created_at": "Tue May 24 18:04:53 +0800 2011",
"id": 11142488790,
"text": "我的相機到了。",
"source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>",
"favorited": false,
"truncated": false,
"in_reply_to_status_id": "",
"in_reply_to_user_id": "",
"in_reply_to_screen_name": "",
"geo": null,
"mid": "5610221544300749636",
"annotations": [],
"reposts_count": 5,
"comments_count": 8
},
"allow_all_comment": true,
"avatar_large": "http://tp1.sinaimg.cn/1404376560/180/0/1",
"verified_reason": "",
"follow_me": false,
"online_status": 0,
"bi_followers_count": 215
},
...
],
"next_cursor": 5,
"previous_cursor": 0,
"total_number": 668
}
- 面向物件設計:使用者是一個完整的物件,其中每個使用者包含一個最新微博的物件,微博物件也是一個相對完整的物件,按照新浪微博的APP介面設計,獲取每一個使用者列表,都能獲取到列表使用者的最新微博資訊。
- 錯誤資訊的返回:主介面中沒有直接對錯誤資訊的定義,但凡是能夠獲取到資訊,都認為是正確,而錯誤資訊的定義則是用另一種資料格式來表示。
{
"request" : "/statuses/home_timeline.json",
"error_code" : "20502",
"error" : "Need you follow uid."
}
- 錯誤資訊的說明:’request’表示當前請求的介面;’error_code’表示錯誤編號;’error’表示錯誤的提示文字
淘寶開放平臺
- 正常響應
{
"user_buyer_get_response":{
"user":{
"nick":"hz0799",
"sex":"m",
"avatar":"http://assets.taobaocdn.com/app/sns/img/default/avatar-120.png",
"open_uid":"324324324"
}
}
}
- 異常響應
{
"error_response":{
"sub_msg":"非法引數",
"code":50,
"sub_code":"isv.invalid-parameter",
"msg":"Remote service error"
}
}
- 錯誤響應也是通過錯誤code來識別的,每個code對應一個錯誤內容
其他開放API
除了上文說的響應方式外,還有一種API響應方式也是比較流行,代表者是百度,高德,支付寶等。
- 百度舉例
{
address: "CN|北京|北京|None|CHINANET|1|None", #詳細地址資訊
content: #結構資訊
{
address: "北京市", #簡要地址資訊
address_detail: #結構化地址資訊
{
city: "北京市", #城市
city_code: 131, #百度城市程式碼
district: "", #區縣
province: "北京市", #省份
street: "", #街道
street_number: "" #門牌號
},
point: #當前城市中心點
{
x: "116.39564504", #當前城市中心點經度
y: "39.92998578" #當前城市中心點緯度
}
},
status: 0 #結果狀態返回碼
}
- 支付寶舉例
{
"alipay_trade_precreate_response": {
"code": "10000",
"msg": "Success",
"out_trade_no": "6823789339978248",
"qr_code": "https://qr.alipay.com/bavh4wjlxf12tper3a"
},
"sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}
- 這類API相對新興設計,在API響應上,不區分正確響應和錯誤響應的結構,採用統一返回方式,其中返回的code 來區分正確還是錯誤,其中的message來分別給出正確和錯誤的響應訊息。
我們自己的API響應規則
選型我們自己使用的API相應規則如下
正常響應示例
{
"status": 1,//狀態值是1
"error_code": 0,//同時錯誤程式碼是0表示無錯誤
"message": "獲取成功",//提示操作成功資訊
"data": []//主體返回內容
}
錯誤響應示例
{
"status": 0,
"error": 20102,//2:業務級錯誤(1程式碼系統級錯誤)固定一個字元;01:指的是01這個業務比如保潔 固定兩個字元;02具體錯誤資訊固定兩個字元,會整理成一個對照表格,前端需要翻譯成友好的提示
"message": "使用者id不能為空",//給前端程式設計師的不友好提示,指明錯誤的原因
"data": {}//data欄位固定
}
小結
- API設計中,要根據自己的業務型別和麵向群體來綜合考慮
- 都對錯誤級別進行了劃分,並用不同的錯誤code來表示
- API面向物件設計並不是面向頁面設計,這樣的API就具有了多端不同展示的能力
- 響應主體設計中,個人比較傾向統一的返回,也就是現在我們正在使用的三段式返回,不同的客戶端不用去寫過多的相容程式碼和錯誤處理,錯誤處理全部由服務端來完成。
- 錯誤處理,目前我們的錯誤處理機制都還比較簡單,就APP而言,只有 ‘0’ ‘1’ ‘1001’,三種識別碼和對應的中文提示內容。如果我們後續要支援多種語言的提示,就必須使用error_code,然後由客戶端自行提示。
介面設計規範
與前端互動部分
這裡概念的定義為與APP部分相互的部分,我們將從安全,版本相容,命名規範,迭代,面向物件等多個方面說起
介面安全部分
在app的後端設計中,一個很重要的因素是考慮通訊的安全性。
避免資訊的洩露,最簡單的方案是所有涉及到安全性的api請求,都必須要使用https協議。
因此,我們需要考慮的要點有:
- 在app和後臺,都不能儲存任何使用者密碼的明文
- 在app和後臺通訊的過程中,怎麼保證使用者資訊的安全性
- 在app中,根據安全考慮,使用者的操作分為兩類:
- 使用者登入
- 註冊操作
使用者的其他操作
- 註冊操作
- 在第一點,使用者登入註冊操作中,是會出現使用者密碼,所以在這個過程中,必須要使用https通訊,保證通訊的安全。
- 在第二點,使用者的其他操作,怎麼保證這部分通訊的安全呢?
在我們的設計中,是採用了公鑰加私鑰保證安全。使用者的id是公鑰,通過一定的演算法對使用者的id進行加密得到一個加密字串是私鑰。當用戶登入或註冊後,通過https把公鑰加私鑰返回給app客戶端。 - 但這個方法有個缺點,當別人截獲了這個url時可以重複使用,所以有個改進方法是在傳遞的引數中增加時間戳,當發現這個時間戳離現在的時間已經很久了,就判斷這個url已經失效了。但用時間戳怎麼保證app的時間和伺服器的時間同步?
可以在app每次啟動和註冊登入時和伺服器同步時間,然後在app內建一個時鐘,時間戳在這個app的內部時鐘獲取,防止使用者修改了手機的時間。 - 當然,這些操作做完了,也不能保證100%的安全,只能為攻擊增加成本。
效率
APP對伺服器端要求是比較嚴格的,在移動端有限的頻寬條件下或者弱網路下,要求介面響應速度要快,,拋開後端的開發框架效率來說,對資料要求也比較嚴格,如果能做到app需要什麼資料就傳什麼資料,不可多傳,過多的資料量影響處理速度,最重要的是影響傳輸效率那麼自然效率是最高的,但是這之間也要有個取捨,效率和介面設計思想之間,後面我們會提到面向物件的設計思想。
面向物件的設計思想
Restful風格:RESTfu設計原則,它被RoyFelding提出(在他的”基於網路的軟體架構”論文中第五章)。而REST的核心原則是將你的API拆分為邏輯上的資源。這些資源通過http被操作(GET,POST,PUT,DELETE)。但現在看,一般的操作只有兩種:GET ,POST。
- 這個設計原則最簡單的應用就是面向物件設計而不是頁面來設計api。最開始的時候,app的一個頁面需要什麼資料,api就返回什麼資料。結果隨著app的UI不斷改版,需要的資料不斷變化,不停地修改api,最後當api的改動會影響以前的版本的時候,只能寫一個新的api版本,最後弄得api中有很多version/2,version/3這樣的標誌,惡夢!
但根據object來設計,又有一個問題,一個大object可能包含很多小object,是一個api返回全部小object,還是分為多個api返回?根據業務和技術,頻寬等仔細考慮吧。 - 目前我們的介面設計是根據業務來定製介面和返回,假設頁面上只顯示五個欄位,那麼後端就需要針對這個頁面進行設計。
- 當然這這樣的好處是顯而易見的,在和客戶端互動的過程中,傳輸的資料全是有用的資料,極大地節約了網路資源,而且只需請求一個介面,介面就返回了所有介面顯示的資料,在弱網狀態下,加快響應速度。
- 新浪微博的做法:打開個人中心,會分多次進行請求,’users/counts’批量獲取使用者的粉絲數、關注數、微博數,’users/domain_show’個性域名相關,’users/show’獲取主要資訊,這是比較極端的做法,僅供參考。
- 下面是一個簡單的例子
返回的資料結構如下
{
"brand_name": "奧迪",
"car_model": "SUV",
"emission_standard": "國五",
"car_owner": {
"name ": "張三 ",
"driving_years": "5年",
"id": "666"
}
}
其中車主是一個物件,車子是一個物件,兩者是既有關係又相對獨立。
總結建議是,新設計的介面,需要考慮到多端不同展示,儘可能的偏向於面向物件,少量特殊處理可以面向頁面。當然,後端程式碼上,都是以物件的形式存在,邏輯必須清楚。
API命名規則
其中一個原則,一看api名字就知道這個api是幹啥。但是有個問題就是當你要負責幾十甚至上百個api,你就知道不能”望名知api”是個什麼樣的痛苦。
就拿一個介面來舉例吧
'/User/userRedDot/version/1'
這是我們在使用的一個介面,從介面名字來看,不難看出User這個是使用者相關的一個功能,然後userRedDot小駝峰命名指的是使用者小紅點,然後介面的版本號是第一版。以上4部分構成了一個完整的介面命名。
傳參規則
介面文件中是會註明不同的介面該使用不同的傳參方式
header引數部分:請求頭部一般放入鑑權的相關引數,比如使用者的token和簽名,裝置id,APP的標識,userAgent自定義等。
除去鑑權的引數,其他就是介面的入參傳遞(文件會註明傳遞方式):
1. 一維引數 按照POST/GET按照普通的form-data和urlencode方式即可
2. 多維引數 按照POST方式,並把body放入json的形式傳遞。
3. 新增資料 POST
4. 獲取資料和修改資料用GET
介面使用規則
系統級介面需要獨立於業務之外使用,對於系統級介面,需遵循介面使用規則,對於非系統級介面,可由具體業務實現。但是安卓和ios需要統一。
打個比方,獲取使用者許可權的介面,介面的使用規則由產品給出的,切換tab和從後臺返回。
再比如,獲取編輯使用者愛好,婚姻情況,個性簽名等篩選資料,按照介面使用規則,應該在進入使用者中心點設定的時候請求,現在是在開啟APP地方的進行請求,不符合介面使用規則。原因也在於以前沒有給出介面使用規則。
特殊處理的介面需要在介面文件上註明使用規則,比如介面的先後順序,介面的使用環境和頻率。
對於介面返回,也需要安卓和ios進行同步處理,操作成功和 操作失敗的資訊提示,成功是都不處理還是都處理,失敗的提示資訊怎麼處理,操作失敗的時候提示資訊需要明確。兩個客戶端不應該存在不同的處理方案。
相容性原則
介面不可能永遠不變,它會隨著需求的變化而做出相應的變動,這種變動也可以理解為相容或者不相容。大部分情況下直接在這個介面上疊加版本號,併兼容舊版本。App的新版本開發傳參時則將傳入新版本的version。
介面的變化一般會有幾種:
1. 資料的變化,比如增加了舊版本不支援的資料型別(相容:新增版本號,介面增量更新)
2. 引數的變化,比如新增了引數(相容:新增版本號,介面增量更新)
3. 介面的廢棄,不再使用該介面了(不相容:原介面指定版本廢棄,後端邏輯處理;原介面所有版本廢棄,如果是業務流程修改,則停用原介面,並新開介面)
4. 如果整個介面系統的根基都發生變動的話,比如微博API,從OAuth1.0升級到OAuth2.0,整個API都進行了升級,就無法相容,只能進行版本強制升級了。
有時候,一個介面的變動還會影響到其他介面,但做的時候不一定能發現。
服務端異常處理
服務端的程式在執行的時候,可能因為一個數據的轉化或空指標異常什麼的,都不能讓程式奔潰,需要捕獲異常並對異常進行處理,並返回明確的資料狀態資訊,不管是成功的,還是失敗的,都必須要有資料返回給APP客戶端,否則,介面的協議失去了所有的意義
app客戶端的語言 java和object-c都是強型別語言,所以怎麼處理空值顯得特別重要,不合理的設計很容易造成app的閃退。
從後臺的角度來說,api中返回的資料中,正確值和空值的型別必須一樣,舉例,使用者名稱的欄位是“realname”: “xxx”,如果使用者名稱為空,則應該返回“realname”:”“。如果返回值是一個array,空資料則返回一個空array,如果返回值是一個物件,空資料則返回一個空物件,絕對禁止null值。
對於客戶端,必須用個全域性的函式來處理所有api的返回資料,需要有一個機制:對於某個客戶端需要資料,如果api中缺失,客戶端自動補上並給予預設值。
同時,在資料庫設計的時候,一個合理的設計必須是所有欄位都有預設值,不應該允許null值。null在大量的語言和資料庫中,會帶來無窮的問題。
如果服務端是php,還有一個問題,php中陣列和字典都是array,但是可以用(object)[]返回物件,但在java和object-c中是不一樣,這個問題一定要注意。
資料格式
補充說明下json的六種資料型別資料型別和約定
- Number:整數或浮點數
- String:字串
- Boolean:true 或 false
- Array:陣列包含在方括號[]中
- Object:物件包含在大括號{}中
- Null:空型別
前後端需要對資料型別進行約定:
- 時間日期型資料:直接返回格式化後的時間字串或者直接返回時間戳
- 數字型別和文字型別:統一使用字串格式
- 布林值型別:統一使用字串’0’和’1’來表示假和真
- 不返回Null型別資料
APP後端程式碼部分
- 面向物件設計,必須具有高拓展性來應對各種需求的變更
- 抽象的顆粒度的把握,顆粒度必須很細,但是又不能太細了,但是實體物件必須是獨立的。
- 程式碼層次結構必須清晰,明確每一層幹什麼事情,做到適當的解耦,不依賴用不到的方法和函式
- 面向介面設計,多人分工合作中,提供的程式碼的最小單位是介面,使用者無需關注介面的內部實現,提供介面的人後期維護該介面。
- 程式碼重合部分,不難發現,目前系統中有很多功能類似的程式碼,但是又發現這些程式碼都有用處,維護這些程式碼就非常痛苦,當要改一個基礎的資料的時候,就會去改很多
- SQL部分,優化SQL查詢,提升查詢效率,杜絕使用join和寫複雜sql等不便於維護的程式碼,不用jion和複雜sql之後能對系統的擴充套件和二次開發有幫助,提高系統和資料庫的併發[目前能知道的是新浪微博已經全面禁止使用join查詢了]。
待商榷問題
- Herder管理:對herder的規劃和規範,包括設計和命名上,還有技術層面上的難題,尤其注意原生裡面的內嵌H5頁面
- push到達率:目前的push能否滿足現狀的需求,如果不滿足,那麼需要怎麼樣才滿足。是否需要引進新的第三方push
- 客戶端更新和熱更新:能否後續的功能用react來編寫,整合熱更新的能力,原生更新的邏輯梳理,和是否合理,不合理該如何調整。
- 許可權和使用者許可權:梳理現在的APP許可權和使用者許可權設計模式和互動模式,看是否合理,不合理的話,怎麼調整。
- 介面依賴關係:介面之間原則上的依賴關係不能超過兩個,意思是一個介面需求的資料,最多隻能從一個介面處獲取,如果情況特殊另說。
關於六大設計模式的補充
以上內容部分引用他出部落格