從零開始的Android新項(xiàng)目9 - 前端用后臺(tái)接口設(shè)計(jì)(教你更好地項(xiàng)目協(xié)作)

這回來(lái)講講后臺(tái)接口的設(shè)計(jì)阁簸。

可能有同學(xué)會(huì)覺得后臺(tái)的接口和我們大前端開發(fā)有什么關(guān)系爬早?試想一下哼丈,在碰到一些不合理的接口設(shè)計(jì)的時(shí)候启妹,你們開發(fā)是否覺得很別扭——需要為了坑爹的接口寫很多臟代碼引坑?甚至醉旦,這么開發(fā)出來(lái)的頁(yè)面饶米,體驗(yàn)也會(huì)很差?我們不是說(shuō)硬無(wú)理要求后端接口按照前端業(yè)務(wù)去封裝车胡,而是說(shuō)為了項(xiàng)目更好地發(fā)展檬输,為了用戶能有更棒的體驗(yàn),應(yīng)該有討論商量的空間匈棘。一些差勁的設(shè)計(jì)丧慈,應(yīng)該被拒絕。

本文使用前端來(lái)指代 Android主卫、iOS 以及 Web逃默。

本文不是教大家撕逼的(趕緊撇清關(guān)系)。

全局

全局指所有接口統(tǒng)一的規(guī)范簇搅。

請(qǐng)求頭

應(yīng)該使用http header來(lái)放置通用性的參數(shù)完域,比如:

  • APPID(Android/iOS/H5)
  • APPVER(版本號(hào))
  • APP-BUILD-NUM(內(nèi)部小版本號(hào))
  • TOKEN
  • NETWORK(網(wǎng)絡(luò)環(huán)境)
  • LANGUAGE(語(yǔ)言)
  • 等等

前端使用 POST 鍵值對(duì)方式提交給后端,可以使用 RawJSON 格式瘩将。
Content-Type 設(shè)為 application/x-www-form-urlencoded 或者 application/json吟税。

全局響應(yīng)格式

響應(yīng)格式應(yīng)該統(tǒng)一凹耙,方便前端做統(tǒng)一的處理,尤其是數(shù)據(jù)字段肠仪,應(yīng)該統(tǒng)一放在一個(gè)map里面肖抱。

名字 類型 詳細(xì)描述
status_no INT 狀態(tài)碼
status_msg STRING 狀態(tài)信息
data MAP 響應(yīng)內(nèi)容
time INT 響應(yīng)時(shí)間戳

狀態(tài)碼

全局應(yīng)該定義統(tǒng)一的狀態(tài)碼(status_code),而不應(yīng)該每個(gè)接口單獨(dú)去定義藤韵。

具體規(guī)則可以自行定義虐沥,比如0為正確,負(fù)數(shù)為錯(cuò)誤泽艘。

常見的錯(cuò)誤狀態(tài)碼有

  • 普通異常
  • token不合法欲险,需要重新登錄
  • 重復(fù)登錄
  • 需要完善個(gè)人信息
  • 第三方賬號(hào)登陸,需要綁定官方賬號(hào)
  • 請(qǐng)求頭不合法(版本號(hào)匹涮,APPID等)
  • 數(shù)據(jù)解密錯(cuò)誤

可以根據(jù)錯(cuò)誤類型劃分使用的區(qū)域段天试,如登陸系列使用 -1000 到 -1999 區(qū)域。

如此定義后然低,前端可以進(jìn)行全局的統(tǒng)一處理喜每,如重復(fù)登陸則踢出用戶。

錯(cuò)誤信息

除了特殊的錯(cuò)誤信息——如重復(fù)登錄雳攘、token不合法這些狀態(tài)碼對(duì)應(yīng)的带兜,以及無(wú)網(wǎng)、沒(méi)數(shù)據(jù)這些吨灭,對(duì)于通用的異常刚照,應(yīng)該由后臺(tái)返回錯(cuò)誤信息。

統(tǒng)一data字段

data 字段應(yīng)該統(tǒng)一放在一個(gè) map 內(nèi)喧兄,里面存放具體的響應(yīng)信息无畔。

Scheme

全局定義統(tǒng)一的 scheme(Deeplink),方便前端進(jìn)行跳轉(zhuǎn)吠冤。

前端只需要定義自己唯一的 Deeplink 并進(jìn)行注冊(cè)即可(scheme 和 host)浑彰。

具體使用 REST 風(fēng)格(如 markzhai://article/XXX),還是普通的 urlencode (如 markzhai://article/?id=XXX&redirect_url=XXX)可以根據(jù)自身需求定義拯辙。

使用 REST 風(fēng)格的一個(gè)顧慮是可能 scheme 本身并不是基于資源的郭变,而是基于類型、行為等涯保,所以 urlencode 可能更通用诉濒,但相應(yīng)地基于 Deeplink 的資源索引會(huì)希望你是無(wú)狀態(tài)的 REST 風(fēng)格。

回傳 or 狀態(tài)碼

應(yīng)該使用回傳還是狀態(tài)碼呢遭赂?比如點(diǎn)贊消息循诉,是應(yīng)該回傳一個(gè) status_code,0則表示點(diǎn)贊成功撇他,還是應(yīng)該回傳現(xiàn)在的贊狀態(tài)呢茄猫?

其實(shí)這兩者對(duì)于后臺(tái)的性能來(lái)說(shuō)狈蚤,是幾乎沒(méi)有影響的,因?yàn)槿〉玫闹皇切薷牡淖侄蔚淖詈蠼Y(jié)果划纽。但是對(duì)前端來(lái)說(shuō)脆侮,差別就有了——需要維護(hù)狀態(tài)。

舉一個(gè)例子:
A 和 B 是兩個(gè)用戶勇劣,B 關(guān)注了 A靖避,A 沒(méi)有關(guān)注 B。
A 看 B 的主頁(yè)的時(shí)候比默,顯示關(guān)系是 未關(guān)注幻捏,此時(shí) A 點(diǎn)擊了關(guān)注,如果沒(méi)有回傳信息命咐,那么我們只能把關(guān)系刷新為 已關(guān)注篡九,而沒(méi)有足夠的信息去刷新為 互相關(guān)注。否則就需要前端去做惡心的邏輯(后端一開始用戶關(guān)系就需要傳 B 關(guān)注了 A)醋奠,根據(jù)原來(lái)的關(guān)系去做切換榛臼,還要在失敗的時(shí)候刷回原來(lái)的狀態(tài)。

一些有豐富經(jīng)驗(yàn)的后端會(huì)在這種接口使用回傳窜司,因?yàn)樗麄冎绤^(qū)別沛善。

模塊vs頁(yè)面

在后臺(tái)的接口設(shè)計(jì)上,又分為了按頁(yè)面以及按模塊塞祈。

按頁(yè)面的接口盡可能讓前端一個(gè)頁(yè)面只請(qǐng)求一次金刁,一次返回所需要的全部信息;按模塊的接口在后端定義自己的業(yè)務(wù)模塊如用戶织咧、Feed胀葱、標(biāo)簽漠秋、搜索等笙蒙,并盡量避免模塊間的耦合。

從后端角度來(lái)說(shuō)庆锦,按模塊當(dāng)然是更好的(只需要?jiǎng)澐值貕蚣?xì)就好)捅位,到時(shí)候需求有什么變更,讓前端自己去改變接口的組合就好搂抒,自己高枕無(wú)憂艇搀。但從前端的角度來(lái)說(shuō),接口的組合涉及到異步之間的關(guān)系求晶,盡管RxJava這樣的響應(yīng)式編程框架讓異步簡(jiǎn)單了很多焰雕,但仍然希望可以避免,更嚴(yán)重的是芳杏,多次接口請(qǐng)求會(huì)讓前端的體驗(yàn)變差矩屁,并行接口的影響稍小辟宗,而一些有前置后置關(guān)系的接口則麻煩比較大,一個(gè)接著一個(gè)請(qǐng)求吝秕,會(huì)讓用戶等很久泊脐。即便是并行接口,有時(shí)候頁(yè)面的渲染仍然需要所有接口數(shù)據(jù)返回后才可以進(jìn)行烁峭。

但如果讓后端按照頁(yè)面去套容客,這樣在后端其實(shí)一樣有性能的損耗,需要一個(gè)頁(yè)面接口去單獨(dú)調(diào)用各個(gè)模塊的接口约郁,然后進(jìn)行組合缩挑。

究竟如何選擇呢?筆者認(rèn)為在服務(wù)器性能足夠的前提下鬓梅,后端應(yīng)該盡量減少頁(yè)面請(qǐng)求次數(shù)调煎,尤其是有依賴關(guān)系的串行請(qǐng)求。另一方面己肮,在一些影響不那么大的頁(yè)面士袄,則可以由前端自行進(jìn)行接口組合(比如上面是用戶主頁(yè)的用戶展示,下面是該用戶的 feed 列表)谎僻。

另外娄柳,如果你們有一個(gè)好的設(shè)計(jì)師,那么他應(yīng)該會(huì)貫徹一個(gè)地方只應(yīng)該以一樣?xùn)|西為主體艘绍,而不應(yīng)該去把亂七八糟的東西拼湊在一起赤拒。

分頁(yè)信息

現(xiàn)代的前端交互上,已經(jīng)很少會(huì)有頁(yè)碼顯示了诱鞠,所以很多后端的列表頁(yè)接口中挎挖,就沒(méi)有帶上了分頁(yè)的信息,而改讓客戶端去維護(hù)請(qǐng)求的頁(yè)碼航夺。

那么蕉朵,分頁(yè)信息在接口中,真的就沒(méi)有存在的必要了嗎阳掐?其實(shí)未必始衅。

為什么需要分頁(yè)信息

頁(yè)面大小(pageSize)可能改變(無(wú)論是前端自己的配置亦或是后臺(tái)修改)缭保,如果僅由客戶端維護(hù)頁(yè)碼汛闸,那么下次請(qǐng)求下一頁(yè)就會(huì)出錯(cuò),除非客戶端帶上自己上次的頁(yè)面大小艺骂。

如果客戶端不知道當(dāng)前頁(yè)碼和總頁(yè)數(shù)诸老,就無(wú)法在請(qǐng)求完判斷底部應(yīng)該顯示上拉加載更多還是沒(méi)數(shù)據(jù)了,導(dǎo)致必須再請(qǐng)求一次钳恕,根據(jù)是否返回 list 以及數(shù)據(jù)是否為空去進(jìn)行判斷别伏。

另外吮廉,由后端返回頁(yè)碼也避免了客戶端修改頁(yè)碼出錯(cuò)的可能。

但對(duì)后端來(lái)說(shuō)畸肆,這些信息的獲取卻意味著更大的計(jì)算和I/O資源損耗宦芦。

折中辦法

折中地,可以讓后端返回一個(gè) has_more 字段轴脐,這樣可以避免最后一次不必要的請(qǐng)求(尤其是數(shù)據(jù)都不夠顯示滿一頁(yè)的情況下)调卑,體驗(yàn)會(huì)好很多。盡管這樣仍然無(wú)法避免頁(yè)面大小改變的問(wèn)題大咱。

配置

一些后臺(tái)喜歡讓讓前端寫限制邏輯恬涧,比如搜索的關(guān)鍵字限制,各種過(guò)濾邏輯碴巾。

咱們先不提讓前端寫死這些邏輯的靈活性問(wèn)題(客戶端和網(wǎng)頁(yè)不同溯捆,不能那么方便地發(fā)版本,即便是網(wǎng)頁(yè)厦瓢,改代碼發(fā)版本就不用測(cè)試了嗎提揍?出了問(wèn)題你背?)煮仇。前端的輸入真的可以信任嗎劳跃?且不談代碼可能寫的不夠嚴(yán)謹(jǐn)導(dǎo)致輸入跳過(guò)了檢查,用戶還能root浙垫、越獄刨仑,甚至可以反編譯客戶端或者直接模擬請(qǐng)求。

所以良好的配置檢查應(yīng)該有兩種

  • 后端下發(fā)配置字段夹姥,前端根據(jù)字段去做對(duì)應(yīng)檢查杉武。好處是減少后臺(tái)壓力,壞處是無(wú)法保證安全性辙售。
  • 后端收到請(qǐng)求自行檢查過(guò)濾轻抱,如果出錯(cuò)則返回錯(cuò)誤信息給前端顯示。

毋庸置疑圾亏,后者更好十拣。

另外封拧,再說(shuō)說(shuō)靈活性志鹃。今天可能限制3個(gè)字,明天產(chǎn)品需求可能就是4個(gè)字泽西,現(xiàn)在產(chǎn)品/運(yùn)營(yíng)說(shuō)不會(huì)改曹铃,到時(shí)候難道就真的一定不會(huì)改嗎?

空字段

一些空字段捧杉,如果沒(méi)有陕见,服務(wù)端應(yīng)該返回一個(gè)空的默認(rèn)字段 比如 String 用""秘血,int 用 0,Object 用 {}评甜,Array 用 []灰粮,這樣減小前端校驗(yàn)?zāi)承┬r?yàn)漏了出現(xiàn)錯(cuò)誤的情況。

                    ---- 由三帥泥阿布補(bǔ)充

我個(gè)人認(rèn)為這樣本身對(duì)流量損耗不大忍坷,且確實(shí)避免了很多可能的異常粘舟,是個(gè)很好的意見。當(dāng)然了佩研,正如后端不應(yīng)該相信前端的輸入一樣柑肴,前端也不能相信后端數(shù)據(jù)的完備性,仍然還是需要悲劇地去校驗(yàn)旬薯。

教訓(xùn)

  • 不要相信什么以后重構(gòu)晰骑,接口現(xiàn)在這么說(shuō),以后他會(huì)告訴你绊序,沒(méi)法兼容老版本所以只能這樣了(甚至搞出兩套規(guī)則讓你同時(shí)兼容)硕舆。

  • 不是說(shuō)后端就是老大。大家的目標(biāo)都是為了項(xiàng)目能做好骤公,而現(xiàn)在通常前端的壓力比后端更大(前端寫得頭昏腦花岗宣,后端網(wǎng)上東逛西逛),所以在不會(huì)很大影響性能的前提下淋样,應(yīng)該滿足前端的合理需求耗式。體驗(yàn)為先。(硬氣一點(diǎn)趁猴,老大應(yīng)該挺你刊咳,甚至親自去撕逼,大不了找CTO)

  • 接口的頻繁修改要向上反饋儡司,測(cè)試數(shù)據(jù)不滿足要求也要及時(shí)提出娱挨。咱們不做背鍋俠。

  • 靈活捕犬,靈活跷坝。做各種需求的時(shí)候,想一想碉碉,這兒會(huì)不會(huì)改變柴钻?就算現(xiàn)在不會(huì)變,以后就不會(huì)變嗎垢粮?比如抽屜里的入口贴届,是不是要做成可配置的?多問(wèn)問(wèn),實(shí)現(xiàn)上盡量靈活毫蚓。

總結(jié)

本篇講了很多通用的后端接口設(shè)計(jì)問(wèn)題占键。幫助大家在面對(duì)一些不合理的接口設(shè)計(jì)時(shí),能進(jìn)行友善的討論(撕逼)元潘,讓項(xiàng)目能做得更好畔乙。歡迎各位在評(píng)論里或者通過(guò)郵件(zhaiyifan56@gmail.com)補(bǔ)充其他點(diǎn),我會(huì)標(biāo)注出來(lái)源翩概。


歡迎加入QQ群:568863373啸澡。

歡迎關(guān)注我們的公眾號(hào):魔都三帥,歡迎大家來(lái)投稿~只需要是未在微信平臺(tái)上發(fā)布過(guò)的技術(shù)相關(guān)類文章都可以哦(不局限于任何語(yǔ)言和平臺(tái))氮帐。

公眾號(hào)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嗅虏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子上沐,更是在濱河造成了極大的恐慌皮服,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件参咙,死亡現(xiàn)場(chǎng)離奇詭異龄广,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蕴侧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門择同,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人净宵,你說(shuō)我怎么就攤上這事敲才。” “怎么了择葡?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵紧武,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我敏储,道長(zhǎng)阻星,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任已添,我火速辦了婚禮妥箕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘更舞。我一直安慰自己畦幢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布疏哗。 她就那樣靜靜地躺著呛讲,像睡著了一般禾怠。 火紅的嫁衣襯著肌膚如雪返奉。 梳的紋絲不亂的頭發(fā)上贝搁,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音芽偏,去河邊找鬼雷逆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛污尉,可吹牛的內(nèi)容都是我干的膀哲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼被碗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼某宪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起锐朴,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兴喂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后焚志,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衣迷,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年酱酬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壶谒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膳沽,死狀恐怖汗菜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挑社,我是刑警寧澤呵俏,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站滔灶,受9級(jí)特大地震影響普碎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜录平,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一麻车、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧斗这,春花似錦动猬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春彼水,著一層夾襖步出監(jiān)牢的瞬間崔拥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工凤覆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留链瓦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓盯桦,卻偏偏與公主長(zhǎng)得像慈俯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拥峦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,070評(píng)論 25 707
  • 前言 兵馬未動(dòng)贴膘,糧草先行。在一款A(yù)PP產(chǎn)品的各個(gè)版本迭代中略号,兵馬的啟動(dòng)指的是真正開始敲代碼的時(shí)候刑峡,糧草先行則是指前...
    listen2code閱讀 18,018評(píng)論 51 220
  • 片段 二: 選自《非暴力溝通》 R:原文 非暴力溝通第二個(gè)要素是感受。心理學(xué)家羅洛.梅認(rèn)為”成熟的人十分敏銳璃哟,就像...
    vege81閱讀 208評(píng)論 0 0
  • 我曾經(jīng)和一個(gè)人約定好了氛琢,若他死了,我便同他離去随闪,在另一個(gè)世界繼續(xù)做他的密探阳似。 但是后來(lái)我違約了。 魔種的生命是要比...
    帥氣的濟(jì)南蜀黍閱讀 2,955評(píng)論 0 8
  • 你也許不會(huì)相信铐伴,我常常想象你是多么美好撮奏,多么可愛,但實(shí)際見了你面的時(shí)候当宴,你比我想象的要美好得多畜吊,可愛得多。 你不能...
    青一墨閱讀 640評(píng)論 0 2