1嘉熊、前言
在日常開(kāi)發(fā)過(guò)程中,大家經(jīng)常都會(huì)遇到:新需求來(lái)了扬舒,但是需要跟第三方接口來(lái)對(duì)接阐肤,第三方服務(wù)還沒(méi)好,我們自己的功能設(shè)計(jì)如何繼續(xù)呢讲坎?這里孕惜,給大家推薦一下Mock方案。
2晨炕、場(chǎng)景示例
2.1衫画、場(chǎng)景一:公司外部間的接口調(diào)用
我們都知道,聯(lián)調(diào)外部接口瓮栗,往往都需要申請(qǐng)測(cè)試環(huán)境削罩,而申請(qǐng)外部測(cè)試環(huán)境的時(shí)間往往都很長(zhǎng)、會(huì)耗費(fèi)很多精力费奸。當(dāng)然弥激,一般都是項(xiàng)目經(jīng)理去協(xié)調(diào)的,但是作為有擔(dān)當(dāng)?shù)拈_(kāi)發(fā)人員愿阐,不可能在這個(gè)空窗期摸魚(yú)劃水吧秆撮。不然,等環(huán)境下來(lái)之后换况,可就是自己苦日子的開(kāi)始职辨,畢竟,不催工期的項(xiàng)目經(jīng)理還是少見(jiàn)的戈二。
2.2舒裤、場(chǎng)景二:公司內(nèi)部之間的接口調(diào)用
曾經(jīng)有一個(gè)項(xiàng)目需要我們配合另一個(gè)部門一起做。需求宣講完后就是定排期觉吭,然后我們就問(wèn)合作部門:“這幾個(gè)接口什么時(shí)候可以聯(lián)調(diào)腾供?”
因?yàn)楹献鞑块T還在趕另外一個(gè)項(xiàng)目,便回復(fù)道:“我們先一起對(duì)接口鲜滩,等忙完手頭這個(gè)項(xiàng)目伴鳖,再給出排期可以嗎?”
然后我們催促道:“那也得給出一個(gè)具體的上線計(jì)劃搬愎琛榜聂?”
在我們的催促下,合作部門終于給出了一個(gè)日期嗓蘑。
過(guò)了幾天须肆,合作部門手頭的項(xiàng)目出現(xiàn)了延期匿乃,又跑過(guò)來(lái)跟我們說(shuō):“我們可能晚幾天才能提供那些接口⊥慊悖”
因?yàn)樾枰c對(duì)方交互的接口的功能遲遲未動(dòng)幢炸,我們也不敢釋放人手,擔(dān)心人手釋放后拒贱,項(xiàng)目又立馬啟動(dòng)宛徊,開(kāi)發(fā)人員好不容易熟悉了新項(xiàng)目又要回來(lái)做這個(gè)。
為此逻澳,我們坐在一起商量了一個(gè)解決思路:
3岩调、解決思路
我們希望有一個(gè) Mock 接口服務(wù),它能提供與正式服務(wù)的 URI赡盘、出入?yún)⒁粯拥慕涌冢瑓^(qū)別是主機(jī)名或者 URL 的前綴不一樣缰揪。
在開(kāi)發(fā)和測(cè)試過(guò)程中陨享,我們都連接上 Mock 服務(wù)。等到接口或環(huán)境搭建好后钝腺,我們無(wú)須修改代碼抛姑,通過(guò)一個(gè)簡(jiǎn)單的配置切換即可讓服務(wù)連接到真實(shí)接口服務(wù),然后通過(guò)一些簡(jiǎn)單的回歸測(cè)試即可實(shí)現(xiàn)上線艳狐,大大提升了開(kāi)發(fā)效率定硝,此時(shí)整體的系統(tǒng)架構(gòu)如下圖所示:
不過(guò),如果我們想實(shí)現(xiàn)這一思路毫目,可就一點(diǎn)不簡(jiǎn)單了蔬啡,因?yàn)樗薓ock服務(wù)端和Mock服務(wù)客戶端調(diào)用設(shè)計(jì)。
4镀虐、Mock服務(wù)端設(shè)計(jì)
先說(shuō)下在Mock服務(wù)端設(shè)計(jì)過(guò)程中箱蟆,都需要滿足哪些需求?
4.1刮便、Mock接口支持返回動(dòng)態(tài)字段數(shù)據(jù)
比如有個(gè)接口輸入的參數(shù)為userId空猜、orderid、redirectUrl恨旱,如下所示:
輸出參數(shù)為success和startTime辈毯,如下所示:
我們希望每次調(diào)用這個(gè)Mock接口時(shí),startTime都返回當(dāng)前時(shí)間搜贤,如:
{
success:true,
startTime:2023-11-12 12:45:02
}
4.2谆沃、Mock接口支持一些簡(jiǎn)單邏輯
在測(cè)試過(guò)程中,我們會(huì)通過(guò)不同的測(cè)試用例走完不同的流程仪芒。
緊接著上面的例子管毙,比如我們希望調(diào)用 Mock 接口傳入的 UserID 是 10001腿椎,那么 Mock 接口返回的 success 值為 True,否則為 False夭咬,而后系統(tǒng)會(huì)根據(jù)不同的 success 值進(jìn)入不同的流程啃炸。
4.3、Mock接口支持回調(diào)
在實(shí)際開(kāi)發(fā)工作中卓舵,有很多聯(lián)調(diào)接口需要異步回調(diào)南用,比如上面的例子中,如果返回的 success 值是 True掏湾,我們希望過(guò)一段時(shí)間回調(diào) Redirect URL裹虫。
4.4、Mock接口支持規(guī)則校驗(yàn)
我們希望通過(guò)添加一些規(guī)則讓這個(gè) Mock 服務(wù)對(duì)傳入的參數(shù)進(jìn)行校驗(yàn)融击,比如校驗(yàn) UserID 是否為數(shù)字筑公、OrderID 是否為 15 位數(shù)字、Redirect URL 是否為 URL……
4.5尊浪、Mock接口支持接口文檔導(dǎo)入
這一點(diǎn)比較特別匣屡,比如某些團(tuán)隊(duì)在設(shè)計(jì)接口文檔時(shí),直接將接口定義放在 Wiki 上拇涤;而某些團(tuán)隊(duì)直接寫在 Java 代碼中捣作,再通過(guò) Swagger 生成在線接口文檔。
對(duì)于前者鹅士,我們要求定義接口時(shí)券躁,直接將接口文檔放在新的 Mock 服務(wù)上。而對(duì)于后者掉盅,因?yàn)椴幌敫淖兯麄兊牧?xí)慣也拜,所以最終 Mock 服務(wù)需要支持 Swagger 文檔導(dǎo)入。
根據(jù)以上五點(diǎn)需求趾痘,我們開(kāi)始在市面上找一些合適的開(kāi)源框架搪泳,并發(fā)現(xiàn)市面上收費(fèi)的接口文檔管理工具有 Apizza、Eolinker扼脐,免費(fèi)的有 YAPI 和 RAP2岸军,出于各種原因的考慮,最終我們決定在 YAPI 和 RAP2 中進(jìn)行選擇瓦侮。
這里我們可以看一下YAPI和RAP2對(duì)比:
通過(guò)表中的內(nèi)容對(duì)比艰赞,很明顯YAPI更符合我們的需求。因此肚吏,在Mock服務(wù)端設(shè)計(jì)過(guò)程中方妖,我們選擇基于YAPI進(jìn)行二次開(kāi)發(fā)。
5罚攀、Mock服務(wù)客戶端調(diào)用設(shè)計(jì)
說(shuō)完Mock服務(wù)端党觅,接下來(lái)我們看看調(diào)用Mock服務(wù)客戶端時(shí)雌澄,都需要考慮什么?
5.1杯瞻、Mock服務(wù)如何支持基于二進(jìn)制流的接口調(diào)用镐牺?
因?yàn)闅v史原因,有些服務(wù)間調(diào)用使用 Spring Cloud Feign 魁莉,而有些服務(wù)間調(diào)用使用基于二進(jìn)制流序列化的 RPC(當(dāng)然是基于 TOP 協(xié)議)睬涧。
我們知道,如果服務(wù)間的通訊是基于二進(jìn)制流而不是 JSON旗唁,就沒(méi)辦法在 YAPI 上通過(guò)簡(jiǎn)單的界面定義輸入輸出參數(shù)了畦浓,且 YAPI 也不支持二進(jìn)制流的調(diào)用,此時(shí)我們的解決方案如下圖所示:
在上面框架中检疫,我們添加了一個(gè)攔截器讶请,它會(huì)攔截所有服務(wù)間調(diào)用的請(qǐng)求,并增加一個(gè)判斷屎媳。如果訪問(wèn)的地址是 Mock 服務(wù)夺溢,我們就使用 HTTP 協(xié)議,并且通過(guò) JSON 進(jìn)行序列化和反序列剿牺,這樣問(wèn)題就解決了。
這里环壤,我們需要補(bǔ)充一點(diǎn):曾經(jīng)晒来,我還碰到過(guò)一些第三方接口使用 XML 格式(很多銀行的接口就是這樣),最終我們決定先不支持自定義XML格式的接口郑现,因?yàn)楦脑?YAPI 的工作量實(shí)在太大湃崩。
5.2、Mock服務(wù)客戶端如何簡(jiǎn)單切換Mock與真實(shí)服務(wù)接箫?
這里攒读,我們需要考慮以下兩種情況:
- 對(duì)于第三方接口,我們只需在配置中將第三方接口的 host 改為 Mock 服務(wù)的 host 即可辛友。
- 對(duì)于微服務(wù)間的調(diào)用薄扁,我們知道 Spring Cloud 中的微服務(wù)定義都是服務(wù)級(jí)別,但是在實(shí)際開(kāi)發(fā)的場(chǎng)景中废累,我們需要使用接口級(jí)別的 Mock邓梅,比如我們開(kāi)發(fā)的 operationService,它依賴 productService 的幾個(gè)接口邑滨。因此日缨,在新項(xiàng)目中,我們還需要在 productService 中新增幾個(gè)接口掖看,且它們必須調(diào)用 Mock 服務(wù)的接口匣距,而原先的接口繼續(xù)調(diào)用真實(shí)的 productService 中原來(lái)已經(jīng)做好的接口面哥。此時(shí),我們需要在配置中心增加 2 個(gè)配置項(xiàng):mock.apis 和 mock.host毅待,每次服務(wù)間調(diào)用時(shí)尚卫,先判斷調(diào)用的 URI 是否在 mock.apis 字符串列表中,如果在恩静,則讓它調(diào)用 mock.host 這臺(tái)機(jī)器焕毫。特別說(shuō)明一點(diǎn):關(guān)于這點(diǎn),曾經(jīng)我們也出過(guò)錯(cuò)驶乾。因?yàn)樵谏暇€時(shí)配錯(cuò)了 mock.apis 和 mock.host邑飒,導(dǎo)致線上環(huán)境使用了 Mock 服務(wù)的情況,所以我們需要多考慮下面這點(diǎn)级乐。
5.3疙咸、如何預(yù)防線上環(huán)境使用Mock服務(wù)?
對(duì)于此問(wèn)題风科,我們做了一個(gè)檢查代碼:在服務(wù)啟動(dòng)時(shí)撒轮,先判斷當(dāng)前的環(huán)境名稱,如果是 prod(線上環(huán)境)贼穆,先判斷 mock.apis 中是否有值题山,有值的話提示異常。然后掃描所有的 properties 配置故痊,如果配置中包含 Mock 服務(wù)地址顶瞳,則說(shuō)明有些地方配置了 Mock 服務(wù)的調(diào)用市框,也提示異常斜友。
到這里铁坎,整體的 Mock 調(diào)用方案就完成了已烤。
以上肆汹,就是關(guān)于Mock服務(wù)端與客戶端的設(shè)計(jì)與實(shí)現(xiàn)思路芋浮,有更好的方案或思路招狸,
可以聯(lián)系我哦: