1.14.1 統一返回的格式
很明顯地,默認情況下,我們選擇了 JSON 作為統一的格式返回接口結果。這里簡單說明一下選取JSON統一返回的原因:
- JSON當前很流行,且普通接口都采用此格式返回
- JSON在絕大部分開發語言中都支持,跨語言
-
JSON在瀏覽器瀏覽時,有可視化插件支持,如FF下:
1.14.2 統一返回結構
通常,我們正常情況下請求接口會返回類似:
1 { 2 "ret": 200, 3 "data": { 4 "title": "Default Api", 5 "content": "PHPer您好,歡迎使用PhalApi!", 6 "version": "1.1.0", 7 "time": 1423142802 8 }, 9 "msg": "" 10 }
其中,ret表示為返回狀態碼,200表示成功;data為領域業務數據,由接口自定義;最后msg為錯誤的提示信息。下面分別解釋之。
(1)返回狀態碼 ret
參照HTTP的狀態碼,特約定:
- 200:接口正常請求並返回
- 4XX:客戶端非法請求
- 5XX:服務器運行錯誤
200 正常返回
當返回200時,需要同時返回data部分數據,以便客戶端實現所需要的業務功能。
4XX 客戶端非法請求
此類請求是由客戶端不正確調用引起的,如請求的接口服務不存在,或者接口參數不對,驗證失敗等等。當這種情況發生時,客戶端同學只需要調整修正調用即可。
對於此系統的狀態碼,在進行接口開發時,可由項目自已定義約定。 通常地,我們需要告知客戶端簽名失敗時,可以這樣:
throw new PhalApi_Exception_BadRequest('wrong sign', 1);
即拋出PhalApi_Exception_BadRequest異常即可,錯誤信息會返回客戶端,對應msg字段;狀態為1,系統對此類的異常會在400基礎上相加的,即:401 = 400 + 1 。
5XX 服務器運行錯誤
此類錯誤是應該避免的,但當客戶端發現有這種情況時,應該知會后台接口開發人員進行修正。
如當配置的參數規則不符合要求時,或者獲取了不存在的參數等即會觸發此類異常錯誤,通常由框架拋出。
(2)業務數據 data
data為接口和客戶端主要溝通對接的數據部分,可以為任何類型,由接口自定義。但為了更好地擴展、向后兼容,建議都使用array。
返回格式的定義與在線查看
當我們在開發接口時,可以通過為接口添加注釋的方式來定義接口的返回格式,然后就可以為外部提供在線文檔的實時查看了。
如:
1 <?php 2 3 class Api_User extends PhalApi_Api { 4 5 /** 6 * 獲取用戶基本信息 7 * @desc 用於獲取單個用戶基本信息 8 * @return int code 操作碼,0表示成功,1表示用戶不存在 9 * @return object info 用戶信息對象 10 * @return int info.id 用戶ID 11 * @return string info.name 用戶名字 12 * @return string info.note 用戶來源 13 * @return string msg 提示信息 14 */ 15 public function getBaseInfo() { 16 // ... ... 17 }
然后在瀏覽器訪問:
http://demo.phalapi.net/checkApiParams.php?service=User.getBaseInfo
可以看到:
注釋格式
格式是以docs的 return 注釋來標明的,其格式為:
@return 返回的類型 字段名字路徑(以點號連接) 字段名字及解析
其中,返回的類型可以為:
關鍵字 | 說明 |
---|---|
string | 字符串 |
int | 整型 |
float | 浮點型 |
boolean | 布爾型 |
date | 日期 |
array | 數組 |
fixed | 固定值 |
enum | 枚舉類型 |
object | 對象 |
溫馨提示:array與object的區別
array是指沒有下標的一個數組集合,或者有下標但下標是連續的自然數,且各元素的結構相同;object則是指一個結構體,類似字典。
此外,為了明確數組與對象間的返回格式,我們也推薦如果是元素來自數組,則在返回字段的后面添加方括號來表明,以提醒客戶端在接收到此類返回時需要循環處理。如:
* @return array list 用戶列表
* @return int list[].id 用戶ID
* @return string list[].name 用戶名字
* @return string list[].note 用戶來源
當需要對接口進行更多說明時,可使用@desc注釋,即:
* @desc 用於獲取單個用戶基本信息
(3)錯誤信息 msg
當返回狀態碼不為200時,此字段不為空。即當有異常(如上面所說的客戶端非法請求和服務端運行錯誤兩大類)觸發時,會自動將異常的錯誤信息作為錯誤信息msg返回。
但對於服務端的異常,出於對接口隱私的保護,框架在錯誤信息時沒有過於具體地描述;相反,對於客戶端的異常,由會進行必要的說明,以提醒客戶端該如何進行調用調整。
此外,我們根據需要可以考慮是否需要進行國際化的翻譯。如果項目在可預見的范圍內需要部署到國外時,提前做好翻譯的准備是很有幫助的。如下,開發時可以這樣返回異常錯誤信息:
throw new PhalApi_Exception_BadRequest(T('wrong sign'), 1);
1.14.3 關於Exception類異常沒捕捉的原因
我們沒有對Exception類的異常進行捕捉,封裝返回非200的形式,是因為我們出於以下的考慮:
- 一來為了方便開發過程中快速發現及定位具體出錯的位置;
- 二來為了便於線上環境中nginx服務器對錯誤的捕捉和紀錄;
1.14.4 JsonP格式和其他的返回
在部分H5頁面異步請求的情況下,客戶端需要我們返回JSONP格式的結果,則可以這樣在入口文件重新注冊response:
if (!empty($_GET['callback'])) {
DI()->response = new PhalApi_Response_JsonP($_GET['callback']);
}
但是在測試環境中,我們是不希望有內容輸出的,所以我們可以測試時這樣注冊response:
DI()->response = 'PhalApi_Response_Explorer';
1.14.5 擴展你的返回格式
當你的項目需要返回其他格式時,如返回XML,則可以先這樣實現你的格式類:
class MyResponse_XML extends PhalApi_Response {
protected function formatResult($result) {
//TODO:把數組$result格式化成XML ...
}
}
隨后,也是簡單重新注冊一下即可:
DI()->response = 'MyResponse_XML';
1.14.6 各狀態碼產生的時機
1.14.7 更好地建議
很多時候,很多業務場景,客戶端在完成一個接口請求並獲取到所需要的數據后,需要進行不同的處理的。
- 就登錄來說,當登錄失敗時,可能需要知道:
- 是否用戶名不存在?
- 是否密碼錯誤?
- 是否已被系統屏蔽?
- 是否密碼錯誤次數超過了最大的重試次數?
- ...
顯然,這里也有一個返回狀態碼,更准備來說,是業務操作狀態碼。並且,此類的狀態依接口不同而不同,很難做到統一。
SO?
我們建議的是,項目接口在業務數據data里面統一再定義一個狀態碼,通常為code字段,完整路徑即: data.code ,同時為0時表示操作成功,非0時為不同的失敗場景。如上面的登錄:
- code = 0 登錄成功
- code = 1 用戶名不存在
- code = 2 密碼錯誤
- code = 3 系統已屏蔽此賬號
- code = 4 密碼錯誤次數超過了最大的重試次數
- ...
最后,客戶端在獲取到接口返回的數據后,先統一判斷ret是否正常請求並正常返回,即ret = 200;若是,則再各自判斷操作狀態碼code是否為0,如果不為0,則提示相應的文案並進行相應的引導,如果為0,則走正常流程!
1.14.8 領域特定設計與Fiat標准
在《RESTful Web APIs》一書中提及到,標准可以划歸到4個分類,分別是:fiat標准、個人標准、公司標准以及開放標准。
顯然,我們這里推薦的是 JSON + ret-data-msg 返回格式既不是個人標准,也不是公司標准(就筆者觀察的范籌而言,未發現某個公司定義了此格式)。而且,也不屬於開放標准,因為也還沒達到此程度。更多的,它是fiat標准。
我們很容易發現,身邊的應用、系統以及周圍項目都在使用諸如此類的返回結構格式,如一些AJAX的接口。
當然,我們可希望可以消除語義上的鴻溝,以便在后台接口開發上有一個很好地共識。
同時,JSON + ret-data-msg 返回格式也是一種領域特定的格式,它更多是為app多端獲取業務數據而制作的規范。雖然它不是很完美,不具備自描述消息,也沒有資源鏈接的能力,但我們認為它是一種恰到好處的格式。
在基於JSON通用格式的基礎上,加以 ret-data-msg 的約束,它很好地具備了統一性,可能門檻低,容易理解。
//接口請求格式
http://dev.phalapi.com/demo/?service=User.GetBaseInfo&user_id=帳號ID
//返回結果格式
1 { 2 "ret": 200, 3 "data": { 4 "code": 0, //狀態碼,0表示正常獲取,1表示用戶不存在 5 "msg": "", 6 "info": { //用戶信息 7 "id": "1", //用戶ID 8 "name": "dogstar", //帳號 9 "note": "oschina" //來源 10 } 11 }, 12 "msg": "" 13 }
原地址:http://blog.csdn.net/baple/article/details/52925772