1. 程式人生 > >XX公司APP介面設計規範v1

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協議。

因此,我們需要考慮的要點有:

  1. 在app和後臺,都不能儲存任何使用者密碼的明文
  2. 在app和後臺通訊的過程中,怎麼保證使用者資訊的安全性
  3. 在app中,根據安全考慮,使用者的操作分為兩類:
      1. 使用者登入
      1. 註冊操作
        使用者的其他操作
  4. 在第一點,使用者登入註冊操作中,是會出現使用者密碼,所以在這個過程中,必須要使用https通訊,保證通訊的安全。
  5. 在第二點,使用者的其他操作,怎麼保證這部分通訊的安全呢?
    在我們的設計中,是採用了公鑰加私鑰保證安全。使用者的id是公鑰,通過一定的演算法對使用者的id進行加密得到一個加密字串是私鑰。當用戶登入或註冊後,通過https把公鑰加私鑰返回給app客戶端。
  6. 但這個方法有個缺點,當別人截獲了這個url時可以重複使用,所以有個改進方法是在傳遞的引數中增加時間戳,當發現這個時間戳離現在的時間已經很久了,就判斷這個url已經失效了。但用時間戳怎麼保證app的時間和伺服器的時間同步?
    可以在app每次啟動和註冊登入時和伺服器同步時間,然後在app內建一個時鐘,時間戳在這個app的內部時鐘獲取,防止使用者修改了手機的時間。
  7. 當然,這些操作做完了,也不能保證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’獲取主要資訊,這是比較極端的做法,僅供參考。
  • 下面是一個簡單的例子
    image
    返回的資料結構如下
{
    "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客戶端,否則,介面的協議失去了所有的意義

  1. app客戶端的語言 java和object-c都是強型別語言,所以怎麼處理空值顯得特別重要,不合理的設計很容易造成app的閃退。

  2. 從後臺的角度來說,api中返回的資料中,正確值和空值的型別必須一樣,舉例,使用者名稱的欄位是“realname”: “xxx”,如果使用者名稱為空,則應該返回“realname”:”“。如果返回值是一個array,空資料則返回一個空array,如果返回值是一個物件,空資料則返回一個空物件,絕對禁止null值。

  3. 對於客戶端,必須用個全域性的函式來處理所有api的返回資料,需要有一個機制:對於某個客戶端需要資料,如果api中缺失,客戶端自動補上並給予預設值。

  4. 同時,在資料庫設計的時候,一個合理的設計必須是所有欄位都有預設值,不應該允許null值。null在大量的語言和資料庫中,會帶來無窮的問題。

  5. 如果服務端是php,還有一個問題,php中陣列和字典都是array,但是可以用(object)[]返回物件,但在java和object-c中是不一樣,這個問題一定要注意。

資料格式

補充說明下json的六種資料型別資料型別和約定

  1. Number:整數或浮點數
  2. String:字串
  3. Boolean:true 或 false
  4. Array:陣列包含在方括號[]中
  5. Object:物件包含在大括號{}中
  6. Null:空型別

前後端需要對資料型別進行約定:
- 時間日期型資料:直接返回格式化後的時間字串或者直接返回時間戳
- 數字型別和文字型別:統一使用字串格式
- 布林值型別:統一使用字串’0’和’1’來表示假和真
- 不返回Null型別資料

APP後端程式碼部分

  • 面向物件設計,必須具有高拓展性來應對各種需求的變更
  • 抽象的顆粒度的把握,顆粒度必須很細,但是又不能太細了,但是實體物件必須是獨立的。
  • 程式碼層次結構必須清晰,明確每一層幹什麼事情,做到適當的解耦,不依賴用不到的方法和函式
  • 面向介面設計,多人分工合作中,提供的程式碼的最小單位是介面,使用者無需關注介面的內部實現,提供介面的人後期維護該介面。
  • 程式碼重合部分,不難發現,目前系統中有很多功能類似的程式碼,但是又發現這些程式碼都有用處,維護這些程式碼就非常痛苦,當要改一個基礎的資料的時候,就會去改很多
  • SQL部分,優化SQL查詢,提升查詢效率,杜絕使用join和寫複雜sql等不便於維護的程式碼,不用jion和複雜sql之後能對系統的擴充套件和二次開發有幫助,提高系統和資料庫的併發[目前能知道的是新浪微博已經全面禁止使用join查詢了]。

待商榷問題

  • Herder管理:對herder的規劃和規範,包括設計和命名上,還有技術層面上的難題,尤其注意原生裡面的內嵌H5頁面
  • push到達率:目前的push能否滿足現狀的需求,如果不滿足,那麼需要怎麼樣才滿足。是否需要引進新的第三方push
  • 客戶端更新和熱更新:能否後續的功能用react來編寫,整合熱更新的能力,原生更新的邏輯梳理,和是否合理,不合理該如何調整。
  • 許可權和使用者許可權:梳理現在的APP許可權和使用者許可權設計模式和互動模式,看是否合理,不合理的話,怎麼調整。
  • 介面依賴關係:介面之間原則上的依賴關係不能超過兩個,意思是一個介面需求的資料,最多隻能從一個介面處獲取,如果情況特殊另說。

關於六大設計模式的補充

以上內容部分引用他出部落格