本人做了3年app相關(guān)的系統(tǒng)架構(gòu),api設(shè)計(jì),先后在3個(gè)創(chuàng)業(yè)公司中工作,經(jīng)歷過(guò)手機(jī)網(wǎng)頁(yè)端,android客戶端,iphone客戶端,現(xiàn)就職于app云后端平臺(tái)bmob(想了解bmob點(diǎn)擊這里)。其中的樂(lè)與苦,得與失,仰首問(wèn)天有誰(shuí)知?我覺(jué)得是時(shí)候來(lái)個(gè)總結(jié),把相關(guān)的技術(shù)和心得記錄下來(lái)。
(1)Restful設(shè)計(jì)原則
Restful風(fēng)格:RESTfu設(shè)計(jì)原則,它被Roy Felding提出(在他的”基于網(wǎng)絡(luò)的軟件架構(gòu)“論文中第五章)。而REST的核心原則是將你的API拆分為邏輯上的資源。這些資源通過(guò)http被操作(GET ,POST,PUT,DELETE)。
但現(xiàn)在看,一般的操作只有兩種:GET ,POST。
這個(gè)設(shè)計(jì)原則最簡(jiǎn)單的應(yīng)用就是根據(jù)object而不是頁(yè)面來(lái)設(shè)計(jì)api。最開(kāi)始的時(shí)候,app的一個(gè)頁(yè)面需要什么數(shù)據(jù),api就返回什么數(shù)據(jù)。結(jié)果隨著app的UI不斷改版,需要的數(shù)據(jù)不斷變化,不停地修改api,最后當(dāng)api的改動(dòng)會(huì)影響以前的版本的時(shí)候,只能寫(xiě)一個(gè)新的api版本,最后弄得api中有很多_V2,V3這樣的標(biāo)志,惡夢(mèng)!
后來(lái)在網(wǎng)站的重構(gòu)過(guò)程中,就根據(jù)object來(lái)設(shè)計(jì)api,但根據(jù)object來(lái)設(shè)計(jì),又有一個(gè)問(wèn)題,一個(gè)大object可能包含很多小object,是一個(gè)api返回全部小object,還是分為多個(gè)api返回?根據(jù)業(yè)務(wù)和技術(shù),帶寬等仔細(xì)考慮吧。
(2) api的命名
其中一個(gè)原則,一看api名字就知道這個(gè)api是干啥。在創(chuàng)業(yè)團(tuán)隊(duì)中,一般就只有一兩個(gè)人負(fù)責(zé)后臺(tái),當(dāng)你要負(fù)責(zé)幾十甚至上百個(gè)api,你就知道不能“望名知api”是個(gè)什么樣的痛苦。
(3) 安全性(下次詳細(xì)解說(shuō))
(4) api返回?cái)?shù)據(jù)
app客戶端的語(yǔ)言 java 和object-c都是強(qiáng)類型語(yǔ)言,所以怎么處理空值顯得特別重要,不合理的設(shè)計(jì)很容易造成app的閃退。
從后臺(tái)的角度來(lái)說(shuō),api中返回的數(shù)據(jù)中,正確值和空值的類型必須一樣,舉例,用戶名的字段是“realname": "xxx”,如果用戶名為空,則應(yīng)該返回“realname": ""。如果返回值是一個(gè)array,空數(shù)據(jù)則返回一個(gè)空array,絕對(duì)禁止null值。
對(duì)于客戶端,必須用個(gè)全局的函數(shù)來(lái)處理所有api的返回?cái)?shù)據(jù),需要有一個(gè)機(jī)制:對(duì)于某個(gè)客戶端需要數(shù)據(jù),如果api中缺失,客戶端自動(dòng)補(bǔ)上并給予默認(rèn)值。這個(gè)機(jī)制在我們的實(shí)踐中大大減少了app的閃退。
同時(shí),在數(shù)據(jù)庫(kù)設(shè)計(jì)的時(shí)候,一個(gè)合理的設(shè)計(jì)必須是所有字段都有默認(rèn)值,不應(yīng)該允許null值。null在大量的語(yǔ)言和數(shù)據(jù)庫(kù)中,會(huì)帶來(lái)無(wú)窮的問(wèn)題。對(duì)于這個(gè)數(shù)據(jù)庫(kù)設(shè)計(jì)原則,我以前不太明白,現(xiàn)在經(jīng)歷了一年的api設(shè)計(jì)后,終于懂得。
如果客戶端是php,還有一個(gè)問(wèn)題,php中數(shù)組和字典都是array,但在java 和object-c中是不一樣,這個(gè)問(wèn)題一定要注意。
(5)圖片的處理
在不同版本的app中,各種不同尺寸的手機(jī)中,同一張圖片顯示的尺寸可能是不一樣,如果每次都需要用返回原圖,然后在客戶端處理,則極大浪費(fèi)網(wǎng)絡(luò)資源。而如果是后臺(tái)處理好圖片才返回,則又是一個(gè)挑戰(zhàn),怎么有效保存和裁剪多種圖片尺寸呢
例如,一開(kāi)始頭像只需要返回60*60的尺寸,后來(lái)在新的版本需要返回70*70, 又出了一個(gè)新版本,需要返回80*80, 每次增加一個(gè)新的尺寸,怎么在數(shù)據(jù)庫(kù)上記錄下來(lái)。這個(gè)問(wèn)題在一開(kāi)始做api的時(shí)候沒(méi)考慮,后來(lái)不得不用了一個(gè)極端的方法,沒(méi)增加新的圖片尺寸,就在數(shù)據(jù)庫(kù)中增加一個(gè)新的字段,保存并生成新的圖片尺寸,結(jié)果最后數(shù)據(jù)庫(kù)的頭像字段有"avatar","avatar_60_60","avatar_70_70","avatar_80_80",這種極度惡虐的設(shè)計(jì)。
最后,針對(duì)圖片,我們才用了這樣的策略:
(1)客戶端本地緩存圖片,只有沒(méi)有合適的圖片,才去服務(wù)器取。
(2)當(dāng)客戶端需要某種尺寸的圖片,由客戶端告訴服務(wù)端圖片的尺寸,服務(wù)端動(dòng)態(tài)生成并緩存起來(lái)。
例如,客戶端需要圖片(http://www.baidu.com/img/bdlogo.gif)的80*80的尺寸,則在圖片的路徑加上寬和高的參數(shù)(類似于CDN的機(jī)制) http://www.baidu.com/img/bdlogo.gif?w=80&h=80, 則服務(wù)器就生成80*80的尺寸并返回。
采用了這樣的圖片處理機(jī)制,數(shù)據(jù)庫(kù)中只要有一個(gè)字段保存原圖就行了,其它尺寸就由客戶端告訴服務(wù)端動(dòng)態(tài)生成。以后無(wú)論什么尺寸的圖片,數(shù)據(jù)庫(kù)中都不需要記錄,數(shù)據(jù)庫(kù)只有原圖就行了。
(6)返回的提示信息
最科學(xué)的情況,服務(wù)端只返回信息代碼,具體的文字提示由客戶端決定。
如果文字信息是由服務(wù)端返回,則最起碼要區(qū)分2種信息:提示用戶的信息,提示客戶端程序員的信息。這兩者的區(qū)別:
1.提示用戶的信息是要在讓客戶知道的,提示客戶端程序員的信息不需要讓客戶知道的。
2. 提示用戶的信息文字很友好,客戶不需要專業(yè)基礎(chǔ)一看就知道是什么,提示客戶端程序員的信息則很專業(yè),例如告訴客戶端少傳了哪個(gè)參數(shù)?哪個(gè)參數(shù)有問(wèn)題等等。
(7)在線api文檔和測(cè)試
我們網(wǎng)站的api在線測(cè)試文檔,既是一份在線api文檔,也是一個(gè)在線測(cè)試工具,極大方便溝通和測(cè)試。每次客戶端程序員覺(jué)得某個(gè)api有什么問(wèn)題,我們就是這個(gè)在線工具上討論溝通的??蛻舳顺绦騿T最喜歡這個(gè)玩意了^-^。
上個(gè)圖解一下饞(這個(gè)圖是舊版的api,已經(jīng)棄用了):

負(fù)責(zé)做這個(gè)功能的同事專門(mén)寫(xiě)了篇博客詳細(xì)介紹了這個(gè)在線api測(cè)試文檔,還帶有demo:
http://amuropikin.iteye.com/blog/1701537
[文章作者]曾健生
[作者郵箱]h6k65@126.com
[作者QQ]190678908
[新浪微博] @newjueqi
[公司網(wǎng)址] www.bmob.cn