關(guān)于處理復(fù)雜邏輯接口重構(gòu)后的驗(yàn)證問題-流量回放

我們經(jīng)常會(huì)重構(gòu)一些復(fù)雜的接口救赐,那么對(duì)于返回字段多并且邏輯復(fù)雜的接口如何來驗(yàn)證?
有如下幾種方案

  1. 重新設(shè)計(jì)经磅,重新設(shè)計(jì)前端的展示邏輯泌绣、后端的查詢計(jì)算邏輯预厌。然后進(jìn)行重寫(最優(yōu)的方案)阿迈。
  2. 假如前端不配合重新搞。要求后端返回的數(shù)據(jù)要和重構(gòu)前的一模一樣仿滔,包括數(shù)據(jù)結(jié)構(gòu)等等。這個(gè)時(shí)候要怎么做呢犹芹?
    2.1. 對(duì)于這種情況下面崎页,我們第一想到的肯定就是不重構(gòu)。但是在不得不重構(gòu)的時(shí)候我們要怎么去重構(gòu)以及重構(gòu)完怎么去測(cè)試驗(yàn)證腰埂?

首先:我們從重構(gòu)的開發(fā)前的設(shè)計(jì)階段入手。

  1. 首先我們重構(gòu)的這個(gè)接口非常復(fù)雜屿笼。所以我們就將這個(gè)整體特別復(fù)雜的接口進(jìn)行拆分,拆分為n個(gè)小邏輯串行的來處理休雌。來保證代碼的可讀性。所以說這個(gè)時(shí)候我們可以使用pipeline設(shè)計(jì)模式來處理,入下圖担扑,每一個(gè)valve里面來處理相應(yīng)的邏輯趣钱。


    image.png
  2. ok現(xiàn)在我們已經(jīng)知道怎么去開發(fā)了。然后開發(fā)完我們?cè)趺慈ヲ?yàn)證是否正確呢燕垃,有上千個(gè)字段井联,并且驗(yàn)證case很多利术?
    2.1 這個(gè)時(shí)候就回到我們的正題了。流量回放
    2.2 流量回放的概念就是將線上的真實(shí)流量進(jìn)行回放一次低矮,要對(duì)于正常的業(yè)務(wù)邏輯無感知的。(并且要保證時(shí)效性)被冒。
    現(xiàn)在是A服務(wù)上面有個(gè)接口要重構(gòu)到B服務(wù)上面军掂。我們這個(gè)流量回放該怎么做轮蜕?
  • 我們先新建一個(gè)服務(wù)C。
  • 再A服務(wù)中需要重構(gòu)的這個(gè)接口后面加一個(gè)發(fā)消息的kafka蝗锥。將請(qǐng)求的參數(shù)以及返回的result跃洛。全部發(fā)到kafka中。
  • 然后我們C服務(wù)來監(jiān)聽這個(gè)kafka消息终议。每當(dāng)這個(gè)kafka過來了汇竭。去請(qǐng)求一下B服務(wù)重構(gòu)后的接口。拿到返回值穴张。然后進(jìn)行返回值的json遞歸對(duì)比细燎。將對(duì)比結(jié)果插入的數(shù)據(jù)庫(kù)。進(jìn)行觀察皂甘,修改即可玻驻。
  • 當(dāng)對(duì)比結(jié)果都沒有差異的時(shí)候,并且已經(jīng)使用線上數(shù)據(jù)進(jìn)行對(duì)比了很長(zhǎng)時(shí)間偿枕。那么這個(gè)時(shí)候我們就可以放心的切流了璧瞬。將流量切到新的接口。
    下面是整個(gè)流程圖
    image.png

    json遞歸對(duì)比代碼

    /**
     * json比較
     */
    public static StringBuffer compareJsonObject(JSONObject aJsonObject, JSONObject bJsonObject, String keyy, List<String> list) {
        StringBuffer sb = new StringBuffer();
        Iterator<String> aKeys = aJsonObject.keySet().iterator();// jsonObject.keys();
        if (null == bJsonObject) {
            sb.append("b中缺失字段,key=").append(keyy).append("的value為null渐夸。a中的value=").append(JSONObject.toJSONString(aJsonObject.keySet())).append(";");
            return sb;
        }
        while (aKeys.hasNext()) {
            String key = aKeys.next();
            if (!(aJsonObject.get(key) instanceof JSONObject) &&
                    !(aJsonObject.get(key) instanceof JSONArray) &&
                    null != aJsonObject.get(key)) {
                Object aFiled = aJsonObject.get(key);
                if (null == bJsonObject.get(key)) {
                    if (list.contains(key)) {
                        continue;
                    }
                    sb.append("字段不同,字段 = ").append(key).append(",aValue = ").append(aFiled).append(";");
                    continue;
                }
                Object bFiled = bJsonObject.get(key);
                if (aFiled instanceof Number) {
                    Number aFiledNumber = (Number) aFiled;
                    if (bFiled instanceof Number) {
                        Number bFiledNumber = (Number) bFiled;
                        if (aFiledNumber.doubleValue() * num == bFiledNumber.doubleValue() * num) {
                            continue;
                        }
                    }
                }
                if (!aFiled.toString().equals(bFiled.toString())) {
                    if (list.contains(key)) {
                        continue;
                    }
                    sb.append("a和b對(duì)比不同,字段 = ").append(key).append(",aValue = ").append(aFiled).append(",bValue = ").append(bFiled).append(";");
                    continue;
                }
            }
            if (aJsonObject.get(key) instanceof JSONObject) {
                if (null == bJsonObject.get(key)) {
                    if (list.contains(key)) {
                        continue;
                    }
                    sb.append("b中缺失此對(duì)象嗤锉,對(duì)象=").append(key).append(",aValue = ").append(JSONObject.toJSONString(aJsonObject.get(key))).append(";");
                    continue;
                }
                if (!(bJsonObject.get(key) instanceof JSONObject)) {
                    if (list.contains(key)) {
                        continue;
                    }
                    sb.append("b中的字段").append(key).append("不是JSONObject類型").append(",aValue = ").append(JSONObject.toJSONString(aJsonObject.get(key))).append(";");
                    continue;
                }
                JSONObject aInnerObject = (JSONObject) aJsonObject.get(key);
                JSONObject bInnerObject = (JSONObject) bJsonObject.get(key);
                sb.append(compareJsonObject(aInnerObject, bInnerObject, key, list));
            } else if (aJsonObject.get(key) instanceof JSONArray) {
                if (null == bJsonObject.get(key)) {
                    if (list.contains(key)) {
                        continue;
                    }
                    sb.append("b中缺失此集合,集合=").append(key).append(",aValue = ").append(aJsonObject.get(key)).append(";");
                    continue;
                }
                if (!(bJsonObject.get(key) instanceof JSONArray)) {
                    if (list.contains(key)) {
                        continue;
                    }
                    sb.append("b中的字段").append(key).append("不是JSONArray類型").append(",aValue = ").append(JSONObject.toJSONString(aJsonObject.get(key))).append(";");
                    continue;
                }
                JSONArray aInnerArray = (JSONArray) aJsonObject.get(key);
                JSONArray bInnerArray = (JSONArray) bJsonObject.get(key);
                sb.append(compareJsonArray(aInnerArray, bInnerArray, key, list));
            }
        }
        return sb;
    }


    private static StringBuffer compareJsonArray(JSONArray aJsonArray, JSONArray bJsonArray, String key, List<String> list) {
        //進(jìn)行排序
        if (key.equals("price_item")){
            aJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("bill_type_name")));
            bJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("bill_type_name")));
        }else if (key.equals("item")){
            aJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("name")));
            bJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("name")));

        }else if (key.equals("spec_req_price_item")){
            aJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("name")));
            bJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("name")));

        }else if (key.equals("porterage_address_item")){
            aJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("k")));
            bJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("k")));

        }else if (key.equals("virtual_phone_info")){
            try {
                aJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("user_phone_no")));
                bJsonArray.sort(Comparator.comparing(item -> ((JSONObject) item).getString("user_phone_no")));
            }catch (Exception e){
                log.error("對(duì)比服務(wù)排序異常",e);
            }

        }
        StringBuffer sb = new StringBuffer();
        if (aJsonArray != null) {
            Iterator aIterator = aJsonArray.iterator();
            if (null == bJsonArray) {
                sb.append("b中的JSONArray為null,key = ").append(key).append(",aValue = ").append(JSONObject.toJSONString(aJsonArray)).append(";");
                return sb;
            }
            Iterator bIterator = bJsonArray.iterator();
            while (aIterator.hasNext()) {
                Object aKey = aIterator.next();
                if (!bIterator.hasNext()) {
                    if (list.contains(key)) {
                        continue;
                    }
                    sb.append("JSONArray b中缺失此集合墓塌,集合=").append(key).append(",aValue = ").append(JSONObject.toJSONString(aKey)).append(";");
                    continue;
                }
                Object bKey = bIterator.next();
                if (aKey instanceof JSONObject) {
                    if (null == bKey) {
                        if (list.contains(key)) {
                            continue;
                        }
                        sb.append("JSONArray b中缺失此對(duì)象瘟忱,對(duì)象=").append(key).append(";");
                        continue;
                    }
                    if (!(bKey instanceof JSONObject)) {
                        sb.append("JSONArray b中的 字段").append(bKey).append("不是JSONObject類型;");
                        continue;
                    }
                    JSONObject aInnerObject = (JSONObject) aKey;
                    JSONObject bInnerObject = (JSONObject) bKey;
                    sb.append(compareJsonObject(aInnerObject, bInnerObject, key, list));
                } else if (aKey instanceof JSONArray) {
                    JSONArray aInnerObject = (JSONArray) aKey;
                    if (null == aInnerObject) {
                        continue;
                    }
                    if (null == bKey) {
                        if (list.contains(key)) {
                            continue;
                        }
                        sb.append("JSONArray b中缺失此集合勾习,集合=").append(key).append(";");
                        continue;
                    }
                    if (!(bKey instanceof JSONArray)) {
                        sb.append("JSONArray b中的 字段").append(bKey).append("不是JSONArray類型;");
                        continue;
                    }
                    JSONArray bInnerObject = (JSONArray) bKey;
                    sb.append(compareJsonArray(aInnerObject, bInnerObject, key, list));
                }
            }
        }
        return sb;
    }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蛤肌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子原献,更是在濱河造成了極大的恐慌态坦,老刑警劉巖盐数,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異伞梯,居然都是意外死亡玫氢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門谜诫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來漾峡,“玉大人,你說我怎么就攤上這事喻旷∩荩” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)槽袄。 經(jīng)常有香客問我烙无,道長(zhǎng),這世上最難降的妖魔是什么遍尺? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任截酷,我火速辦了婚禮,結(jié)果婚禮上乾戏,老公的妹妹穿的比我還像新娘迂苛。我一直安慰自己,他們只是感情好鼓择,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布三幻。 她就那樣靜靜地躺著,像睡著了一般惯退。 火紅的嫁衣襯著肌膚如雪赌髓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天催跪,我揣著相機(jī)與錄音锁蠕,去河邊找鬼。 笑死懊蒸,一個(gè)胖子當(dāng)著我的面吹牛荣倾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播骑丸,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼舌仍,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了通危?” 一聲冷哼從身側(cè)響起铸豁,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎菊碟,沒想到半個(gè)月后节芥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逆害,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年头镊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魄幕。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡相艇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纯陨,到底是詐尸還是另有隱情坛芽,我是刑警寧澤留储,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站靡馁,受9級(jí)特大地震影響欲鹏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜臭墨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望膘盖。 院中可真熱鬧胧弛,春花似錦、人聲如沸侠畔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)软棺。三九已至红竭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喘落,已是汗流浹背茵宪。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘦棋,地道東北人稀火。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赌朋,于是被迫代替她去往敵國(guó)和親凰狞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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