1. 程式人生 > >js 請求異常重連或斷線後聯網重連機制(ajax)

js 請求異常重連或斷線後聯網重連機制(ajax)

    這個需求的應用場景是這樣的,在開發一個基於h5的移動app 時,在請求api 時出現請求的異常或者是請求中途網路中斷的情況,一旦出現問題則需要重新觸發某個點選事件或者開啟某個頁面。於是就想,遇到異常情況我們能不能讓請求自動重連,重新呼叫我們的資料。當然,一開始都是先看看網上的解決方案,但是找了好久沒找到合適的(也可能是自己沒找對關鍵詞,當時搜尋的是 “js斷網重連機制”)。既然沒有的話,就只好自己試一下了(要是哪位朋友有解決方案,希望可以分享一下)。

    簡單的整理一下需要的流程:

    >發起請求

    >如果請求正常,判斷是否是期望的結果(這裡說一下,一般我們的app 可以直接接我們開發的 後臺 api,但是在做這個專案時有點不一樣,在app與api之間多了一個第三方,我們的請求需要請求到第三方(jsp程式),然後第三方再請求我們的真實介面,有點繞,不能代理,第三方在請求異常或者超時時也有他們自己的訊息返回,所以要做好判斷是否是我們的資料)

        >如果資料是我們能 api 返回的 執行 ajax 回撥程式

        >如果資料是第三方的異常資料  嘗試重連(我們的 api 沒問題的話,重新請求一般都是能得到資料的)

    >如果請求異常 嘗試重連

    思路是這樣,但具體實現還是有其它問題的。比如

    1. 怎麼確認是哪個請求出異常並對該請求重連呢?

    2.重連的回撥能否正常執行呢?

    暫時不管上面兩個問題,本文的解決發難如下

   >建立一個 temp 陣列來儲存請求的記錄,每一個呼叫 ajax 請求前都儲存好必要資訊:id(請求標識,標識不同的請求),url,data,callback,reloadtimes(重複請求次數) 。

    >在請求進來時,判斷是否已經在 temp中,不在的話,先儲存到temp 中

    >請求正常的話 從 temp 中移除

    >請求異常的話,嘗試重連

    前面說了這麼多,還是看看程式碼吧。

(function(window) {

        var temp = new Array();

        function removeTemp(obj) {
            var id = obj.id;
            //將請求記錄從 temp 中去掉
            for (var key in temp) {
                if (id == temp[key].id) {
                    console.log("移除:" + temp[key].id);
                    temp.slice(key, 1);
                    break;
                }
            }
        }

        function reconnect(obj) {
            var id = obj.id;
            //這可以寫更多的重連邏輯,比如 每次重連間隔的時間增加
            if (obj.reloadtimes == 10) {
                //將請求記錄從 temp 中去掉
                removeTemp(obj);
            } else {
                obj.reloadtimes++;
                console.log(obj.id + " " + obj.reloadtimes + " 秒 後自動重新連結");
                setTimeout(() => {
                    request(obj.id, obj.url, obj.data, obj.callback);
                }, obj.reloadtimes * 1000); //每次間隔時間遞增
            }
        }
        //請求
        function request(id, url, data, callback) {
            let obj = {
                id: id,
                url: url,
                data: data,
                callback: callback,
                reloadtimes: 0
            };
            //判斷是否已經存在 快取中了,存在則跳過
            let exist = false;
            for (let key in temp) {
                if (id == temp[key].id) {
                    exist = true;
                    obj = temp[key];
                    break;
                }
            }
            //不存在快取中則插入
            if (!exist)
                temp.push(obj);

            $.get(url, data, res => {
                let _obj = obj;
                //判斷正常請求是否符合預期,這裡判斷結果內容是否大於XXX,實際上可以看情況處理
                if (JSON.stringify(res).length > 5) {
                    //移除記錄
                    removeTemp(_obj);
                    callback(res);
                } else {
                    //重連
                    reconnect(_obj);
                }
            }).error(e => {
                //重連
                let _obj = obj;
                console.log(_obj.id + " 請求異常");
                reconnect(_obj);
                //console.log(e);
            });
            //console.log(temp);
        }
        window.request = request;
    }(window))

    用的時候這樣用就行了

    //請求測試
    request("aaaaaaa", "data.html", {}, res => {
        console.log(res);
    });
    request("bbbbbbbb", "data1.html", {}, res => {
        console.log(res);
    });
    request("ccccc", "data1.html", {}, res => {
        console.log(res);
    });
ps:這裡的id 是隨便寫的 aaaaa 什麼的,但實際開發的話,我們使用了 時間戳來作為id

    效果如圖


然後回頭看下那兩個問題

1.本文是通過建立一個物件陣列儲存了請求的必要資訊,滿足請求以及回撥所需引數。

2.這個一開始擔心的是多頁面共同呼叫一個請求,要是切換到另一個頁面會不會有問題,經實踐發現沒有問題(app 用的是 Hbuilder 開發)

ps:這裡處理的是 ajax請求的,但是 如果不用ajax 不知道能否實現呢?還有就是,百度pc 端檢索如果斷網會定期請求重連,但處理方式好像不一樣,哪位朋友瞭解的話,希望能分享一下,謝謝啦!