前后端接口規范


前后端接口規范  來源: https://github.com/f2e-journey/treasure/blob/master/api.md

隨着前后端分離越來越普遍, 后端接口規范也就越來越重要了. 一套良好的接口規范可以提升工作效率, 減少溝通障礙.

通常我們都會采用 REST 方式來提供接口, 使用 JSON 來傳輸數據.

名詞 含義
前端 Web前端, APP端, 桌面端等一切屬於用戶界面的這一層
后端 即服務器端, 指一切屬於用戶界面之下的這一層
前后端接口 前端與后端進行數據交互的統稱, 也叫做數據接口, 屬於一種遠程調用, 一般指前端通過HTTP(ajax)請求獲取到的數據或者執行的某項操作. 為確保前后端(工程師)的協作溝通, 一般由前端和后端一起來定義接口的規范, 規范的內容一般包含接口的地址, 接口的輸入參數和輸出的數據格式(結構), 最終由后端來實現這些規范, 為前端提供符合規范的接口
 [前端] 
--------
   ^
   |
   |
前后端接口
   |
   |
--------
 [后端]

前后端接口協作流程

在開發之前一定要先定義好接口規范, 至於接口應該由前端來定還是后端來定, 這個還得看公司的具體情況, 但一定要讓前后端都確認無誤, 特別是接口協商要點.

以免出現前后端分離之后最容易出現的扯皮現象. 特別是當你碰到做事不主動(無責任感)的后端, 什么都要前端來催. 比如什么接口又缺了一個字段沒有提供啦, 什么又少了一個接口啦, 等等諸如此類. 后端不去熟悉業務, 也不看界面原型和需求, 只管把接口做完, 任務完成就萬事大吉了, 每天除了等前端通知哪里要修改, 自己就像沒事人一樣.

所以說定好接口, 前后端一起來確認好接口是多么的重要, 不然你就等着干着急吧. 當然了, 想一次性完美地將所有接口都定義出來, 有點不太現實, 需要調整的情況在所難免, 所以還是希望后端能夠主動一點, 前后端溝通的時候就輕松得多, 大家的效率就都提高了.

准備環境

接口規范

由前端(APP端)和后端一起協定接口規范的內容, 確定每一個接口的地址(URL), 輸入(request)和輸出(response), 必要的時候詳細注釋每一個字段的含義和數據類型.

具體需要定義哪些接口, 可以按照下面的思路來整理

  • 資源接口: 系統涉及到哪些資源, 按照 RESTful 方式定義的細粒度接口
  • 操作接口: 頁面涉及到哪些操作, 例如修改購物車中商品的數量, 更換優惠券等等, 也可以使用 RESTful 方式來定義
  • 頁面接口: 頁面涉及到太多接口, 如果是一個個地調用, 會需要很多次請求, 有可以影響到前端的性能和用戶感知(特別是首屏的體驗), 因此可能需要將這些接口的數據合並到一起, 作成一個聚合型接口提供給前端來使用

接口協商要點

  • 接口必須返回統一的數據結構, 參考后端接口通用規范中接口返回的數據結構
  • 接口查詢不到數據時, 即空數據的情況下返回給前端怎樣的數據
    • 建議返回非 null 的對應數據類型初始值, 例如對象類型的返回空對象({}), 數組類型的返回空數組([]), 其他原始數據類型(string/number/boolean...)也使用對應的默認值
    • 這樣可以減少前端很多瑣碎的非空判斷, 直接使用接口中的數據
    • 例如: result.fieldName
    • 如果 result 為 null, 可想而知會報錯 Uncaught TypeError: Cannot read property 'fieldName' of null
  • 調用接口業務失敗的常用錯誤碼, 例如未授權時調用需要授權的接口返回 "status": 1
  • 接口需要登錄時如何處理, 特別是同時涉及到 Web 端/微信端/App 端, 需要前端針對運行環境判斷如何跳轉到登錄頁面
  • 返回數據中圖片 URL 是完整的還是部分的
    • http://a.res.com/path/to/img.png 這就是完整的, 前端直接使用這個 URL
    • /path/to/img.png 這就是部分的, 一般省略域名部分, 前端需要自己拼接后才能使用 'http://a.res.com' + '/path/to/img.png'
  • 返回數據中頁面跳轉的 URL 是給完整的還是部分的
    • 內部頁面返回部分的, 或者只給ID, 由前端自己拼接, 例如只給出商品ID, 讓前端自己拼接商品詳情頁的 URL
    • 外部頁面返回完整的, 例如廣告位要跳轉去谷歌
  • 返回數據中日期的格式, 是使用時間戳還是格式化好的文字
    • 對於需要前端再次處理的日期值(例如根據日期計算倒計時), 可以使用時間戳(簡單暴力), 例如: 1458885313711, 或者參考 Date.prototype.toJSON 提供 ISO 標准格式(例如需要考慮時區時)
    • 對於純展示用的日期值, 推薦返回為格式化好的文字, 例如: 2017年1月1日
  • 對於大數字(例如 Java 的 long 類型), 返回給前端時需要設置為字符串類型, 否則 JavaScript 會發生溢出, 造成得到的數值錯誤
    • 例如: 返回 JSON 數據 {"id": 362909601374617692} 前端拿到的值卻是: 362909601374617660
  • 分頁參數和分頁信息
    • 如何限制只返回 N 條數據(limit 參數)
    • 如何控制每頁的數據條數(pageSize 參數)
    • 如何加載某一頁的數據(page 參數)
      • 第一頁是從 0 開始還是從 1 開始
    • 如何避免無限滾動加載可能出現的重復數據(采用 lastId 分頁方式, 來避免傳統分頁方式的弊端)
      • 假設數據是按照新增時間倒序排列的
      • 首先加載 2 頁的數據
      • 等了很久
      • 期間新增了很多數據
      • 再獲取第 3 頁數據
      • 此時就可能出現重復數據的情況, 因為新增的數據都排在最前面, 后面會接着已經加載過數據
    • 分頁信息包含什么(total, page, pageSize)
    • 分頁信息何時表明已經是最后一頁了
      • 請求某頁數據時返回的數據條數 < pageSize
      • 請求某頁數據時返回的數據條數 = 0
      • 如果碰巧最后一頁有 pageSize 條數據, 前端無法通過數據條數來判斷已經處於最后一頁了

接口定義

所有的接口定義在項目前端靜態文件目錄的 _mockserver.json 文件中, 啟動 puer-mock 服務, 即可使用這些接口獲得符合規范的假數據, 也可以查看接口文檔.

具體 puer-mock 的詳細使用手冊和 _mockserver.json 如何配置接口請參考 puer-mock 項目, 或者參考項目中已經配置好的其他接口.

接口協作

由於接口規范的定義和接口的實際實現是分開的兩個部分, 而且涉及到多人協作, 因此在開發過程中可能出現接口規范與實現不同步, 最終造成實際的接口不符合規范的定義, 接口規范就會慢慢失去存在的意義.

為了盡量避免這種問題, 后端在實現接口的過程中應該確保與接口規范保持一致, 一旦出現分歧, 必須同步修改接口規范, 盡可能保持溝通.

接口文檔(示例)

puer-mock-api-doc-html

后端接口通用規范

接口地址和請求方式

接口根路徑 - Root Endpoint 推薦為: http://api.yourdomain.com 或者 http://yourdomain.com/api

接口地址即接口的 URL, 定義時使用相對路徑(即不用帶上域名信息), 建議分模塊來定義, 推薦 REST 風格, 例如

  • GET /user/:id 表示獲取用戶信息
  • POST /user 表示新增用戶

接口參數

向接口傳遞參數時, 如果是少量參數可以作為 URL query string 追加到接口的 URL 中, 或者作為 Content-Type: application/x-www-form-urlencoded 放在請求體(body)中(即表單提交的方式)

對於復雜的接口參數(例如嵌套了多層的數據結構), 推薦在 HTTP 請求體(body)中包含一個 JSON 字符串作為接口的參數, 並設置 Content-Type: application/json; charset=utf-8.

例如

查詢 VIP 用戶的接口

POST /users?limit=10 HTTP/1.1
Content-Type: application/json; charset=utf-8

{
    "name": "hanmeimei",
    "isVip": true
}

接口返回的數據結構

返回的響應體類型推薦為 Content-Type: application/json; charset=utf-8, 返回的數據包含在 HTTP 響應體中, 是一個 JSON Object. 該 Object 可能包含 3 個字段 datastatusstatusInfo

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "data": {},
    "status": 0,
    "statusInfo": {
        "message": "給用戶的提示信息",
        "detail": "用於排查錯誤的詳細錯誤信息"
    }
}
字段名 字段說明
data 業務數據
必須是任意 JSON 數據類型(number/string/boolean/object/array).
推薦始終返回一個 object (即再包一層)以便於擴展字段.
例如: 用戶數據應該返回 {"user":{"name":"test"}}, 而不是直接為 {"name":"test"}
status 狀態碼
必須是 >= 0 的 JSON Number 整數.
  • 0 表示請求處理成功, 此時可以省略 status 字段, 省略時和為 0 時表示同一含義.
  • 非 0 表示發生錯誤時的錯誤碼, 此時可以省略 data 字段, 並視情況輸出 statusInfo 字段作為補充信息
statusInfo 狀態信息
必須是任意 JSON 數據類型.
推薦始終返回一個 object 包含 message 和 detail 字段
  • message 字段作為接口處理失敗時, 給予用戶的友好的提示信息, 即所有給用戶的提示信息都統一由后端來處理.
  • detail 字段用來放置接口處理失敗時的詳細錯誤信息. 只是為了方便排查錯誤, 前端無需使用.

例如

  • 接口處理成功時接口返回的數據

    {
        "data": "api result"
        "status": 0
    }
    
  • 接口處理失敗時接口返回的數據

    {
        "status": 1,
        "statusInfo": {
            "message": "服務器正忙",
            "detail": {
                "exception": "java.util.List"
            }
        }
    }
    

這樣我們就可以非常容易地通過判斷 status 來處理數據了

if (!response.status) { // status 為 0 或者沒有 status 字段時表示接口成功返回了數據 console.log(response.data); } else { // 失敗 console.error(response.status, response.statusInfo); // 統一由服務端返回給用戶的提示信息 alert(response.statusInfo.message); }

錯誤碼規范: status 字段該如何取值

采用前后端分離開發模式的項目越來越多, 前端負責調用后端的接口來展現界面, 如果有界面顯示異常, 需要有快速方便的手段來排查線上錯誤和定位出職責范圍

綜合了經驗總結和行業實踐, 最簡單有效的手段是制定出一套統一的錯誤碼規范, 協助多方人員來排查出接口的錯誤

例如

  • 用戶發現錯誤, 可以截錯誤碼的圖, 就能夠提供有效的信息幫助開發人員排查錯誤
  • 測試人員發現錯誤, 可以通過錯誤碼, 快速定位是前端的問題還是后端接口的問題

因此我們確定提示信息規范為: 當后端接口調用出錯時, 接口提供一個用戶可以理解的錯誤提示, 前端展示給用戶錯誤提示和錯誤碼, 給予用戶反饋

對於錯誤碼的規范, 參考行業實踐, 大致有兩種方案

具體實踐如下

  • 錯誤碼固定長度, 以區間來划分錯誤類型(例如 HTTP 的狀態碼)

    例如: 10404 表示 HTTP 請求 404 錯誤, 20000 表示 API 調用失敗, 30000 代表業務錯誤, 31000 表示業務A錯誤, 32000 表示業務B錯誤

  • 錯誤碼可不固定長度, 以首字母來划分錯誤類型, 可擴展性更好, 但實際運作還是需要划分區間

    例如: H404 表示 HTTP 請求 404 錯誤, A100 表示 API 調用失敗, B100 表示業務A錯誤, B200 表示業務B錯誤

關於錯誤分類的原則, 我們可以根據發送請求的最終狀態來划分

  • 發送失敗(即請求根本就沒有發送出去)
  • 發送成功
    • HTTP 異常狀態(例如 404/500...)
    • HTTP 正常狀態(例如 200)
      • 接口調用成功
      • 接口調用失敗(業務錯誤, 即接口規范中 status 非 0 的情況)

最終規范

錯誤碼可不固定長度, 整體格式為: 字母+數字字母作為錯誤類型, 可擴展性更好, 數字建議划分區間來細分錯誤

例如:

  • A for API: API 調用失敗(請求發送失敗)的錯誤, 例如 A100 表示 URL 非法
  • H for HTTP, HTTP 異常狀態的錯誤, 例如 H404 表示 HTTP 請求404錯誤
  • B for backend or business, 接口調用失敗的錯誤, 例如 B100 業務A錯誤, B200 業務B錯誤
  • C for Client: 客戶端錯誤, 例如 C100 表示解析 JSON 失敗
                                                       發送 HTTP 請求
                                                 ┌───────────┴───────────┐
                                              發送成功¹               發送失敗²
                                                 │                       │
                                      ┌──────────┴──────────┐            A 例如: A100
                                獲得 HTTP 響應       無法獲得 HTTP 響應³
                                      │                     │
                                 HTTP status                A 例如: A200
                           ┌──────────┴──────────┐
                       HTTP 成功(200-300)     HTTP 異常
                           │                     |
               {data, status, statusInfo}        H${HTTP status} 例如: H404
               ┌───────────┴───────────┐
          接口調用成功(status:0)   接口調用失敗
      ┌────────┴────────┐              |
客戶端處理出錯      客戶端處理正常       B${status}${statusInfo.message} 例如: B100
      |
      C 例如: C100

- 發送成功¹: 服務端收到了 HTTP 請求並返回了 HTTP 響應
- 發送失敗²: HTTP 請求沒有發送出去(例如由於跨域被瀏覽器攔截不允許發送), 未到達服務端(即服務端沒有收到這個 HTTP 請求)
- 無法獲得 HTTP 響應³: 服務端收到了請求並返回了響應, 但客戶端由於某些原因無法獲得 HTTP 響應, 例如請求的超時處理機制

統一錯誤提示

  • 錯誤日志
    • 接口調用出錯(${錯誤碼}${HTTP 方法} ${HTTP URL} ${請求參數} ${請求選項} ${請求返回結果}
    • 例如: 接口調用出錯(H404) GET https://domain.com {foo: bar} {option1: 'test'} {status: 404}
  • 給用戶的提示消息(參考自 QQ 的錯誤提示消息)
    • 提示消息(錯誤碼: xxx)

      weapp-error-tip weibo-error-tip qq-error-tip

    • 提示消息和錯誤碼之間用換行隔開

    • 錯誤碼整塊內容建議弱化使用灰色字

    • 例如

      mobile-error-code-message pc-error-code-message

規范實現: weapp-backend-api

接口實現建議

  • 接口實現的大方向建議遵循 RESTful 風格
  • HTTP 動詞: 獲取數據用 GET, 新增/修改/發送數據用 POST
    • 例如: 獲取用戶數據的接口用 GET, 修改用戶數據的接口用 POST
  • 對於資源的操作類型, 使用 HTTP 動詞來指定, 減少接口 URL 的數量
    • 例如: GET /contact 獲取聯系人, POST /contact 新增/修改聯系人
  • 對外的 ID 字段使用字符串類型
    • 特別核心數據的 ID 字段, 不要使用自增的數字類型, 建議使用無規則的字符串類型(例如UUID), 避免核心數據被輕易抓取
    • 避免使用大數字類型(Long), 因為前端可能承載不了這個精度而溢出得到另外一個數值
    • 例如: Java 中的 Long 類型的數值: 362909601374617692, 作為 JSON 數據返回給前端, 前端拿到的值變成了 362909601374617660
  • 接口字段建議同時給出 ID 字段和用於顯示字段, 前端提交數據時只提交 ID 字段
    • 例如: {"sex": 1, "sexText": "男"}
  • 圖片的 URL 建議返回完整的 URL
    • 例如: {"pic": "https://domain.com/a.png"}
  • 時間字段建議同時返回時間戳的原始值(或 ISO 標准格式)和用於統一顯示的格式化文本
    • 由后端接口集中控制各端的顯示, 提供的原始值兼顧前端的自定義顯示或者計算(例如倒計時)的需求
    • 避免每個端(例如H5/APP/小程序)都需要對時間做統一的格式化實現, 一旦需要調整, 需要各個端都調整一遍
    • 例如: {"createTime": 1543195480357, "createTimeText": "2018年11月26日"}
  • 統一分頁的數據格式
    • 分頁請求的參數和分頁結果的數據結構

注意

參考

  • E-JSON數據傳輸標准

  • 有范雲協作 讓項目的協作姿勢更有范兒

    • 交互階段說明
      • 交互設計師根據產品方的需求對產品進行行為設計和界面設計的階段,主要產出物為交互設計稿
      • 開發工程師需要做的事情是針對產品需求、交互設計稿中的內容進行技術評審,為產品方、交互設計師提供可行技術實現解決方案,對於多種不同解決方案需針對各種解決方案做分析說明,務必准確傳達各種方案的優缺點,並根據需求給出建議方案
    • 系統設計說明
      • 各端開發工程師針對產品需求說明、交互設計稿開始設計系統架構、拆分子系統、划分子系統模塊、協調端與端之間的接口規范,這個階段各端根據實際情況輸出若干系統設計說明書等文檔
      • 除此之外更重要的是輸出端與端之間通信的接口規范,而這個規范則可以借助 NEI 平台 來完成
    • 編碼階段說明
      • 開發工程師根據系統設計階段的輸出,用代碼來實現這樣的系統,包括技術方案的選型、項目框架的搭建、工具及環境的配置等
      • 其中有些工作可以借助於有范雲協作提供的自動化工具 NEI-Toolkit 來完成,比如項目的初始結構代碼、在 NEI平台 上定義好的接口規范等
    • 自測階段說明
      • 各個端的工程師驗證自己編寫的代碼的正確性,按角色不同,測試方式也有所有不同
      • 對於前端和移動端工程師來說,主要是需要測試各種可能的值會不會影響界面展示
      • 對於服務端工程師來說,主要是測試提供給客戶端工程師使用的接口的正確性,對於不同的輸入參數是否返回了預期的結果
    • 聯調階段說明
      • 主要是連測試環境進行測試
      • 對於前端和移動端工程師來說,主要是需要將本地容器提供的接口換成測試環境的接口
    • 測試階段說明
      • 開發工程師開發完成后提測的過程,是產品上線前的最后環節
      • 測試工程師會對接 NEI 平台生成接口測試用例代碼並集成到自動化測試平台運行,如果NEI平台的接口定義與實際提測的項目不符則此次提測失敗,需由開發對照 NEI 平台檢查接口實現情況,所以可以保證 NEI 平台上的接口定義始終與線上保持一致
  • 客戶端API請求規范

    參數名 說明
    imei 國際移動設備身份碼
    imsi 客戶端用戶標識
    t TIMESTAMP,請求的時間戳
    appkey 由服務端頒發的appkey
    sign md5簽名串。為了減輕非法惡意請求,每次來自APP的請求都需要對請求參數進行簽名以實現安全認證
    lng 手機上獲取的經度
    lat 手機上獲取的緯度
    ci 渠道標識,格式為:channelId@應用名平台客戶端版本,例如:1001@nzaom_android_1.0,其中1001表示應用寶
  • GitHub API | 微博API | 淘寶開放平台 API

  • JSend | JSON API | JSON Schema | JSON-RPC | JWT | OAuth

    Type Description Required Keys Optional Keys
    success All went well, and (usually) some data was returned. status, data  
    fail There was a problem with the data submitted, or some pre-condition of the API call wasn't satisfied status, data  
    error An error occurred in processing the request, i.e. an exception was thrown status, message code, data
  • Google JSON Style Guide

  • 最佳實踐:更好的設計你的 REST API | RESTful API 設計指南 | Best Practices for Designing a Pragmatic RESTful API | HTTP API Design Guide | The RESTful Cookbook | RESTful API 編寫指南

  • Restlet Studio - Web IDE for API design | Swagger | ReDoc | RAML | API Blueprint


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM