天天看點

前端異常 — 跨終端實時追蹤

我已淪為IE狗!!!

從9月份一開始,新項目正式啟動,産品以用戶端的形式釋出,目前用的是.NET的WebBrowser内嵌網頁的形式開發,對于後端來說,一切都是那麼自然、簡單;可對于前端來說,徹底将我帶入到了IE的黑洞,自此萬劫不複!說實話,我内心無比鄙視這個WebBrowser,因為windows綁定了IE,WebBrowser預設使用IE核心,按理說現在win7及以上系統居多,是以這個核心怎麼也是IE9+居多才對啊,可惡的是,衆多系統都是重裝的非正版閹割後的系統,可惡的是,WebBrowser在這些系統哪怕是裝的win7、IE11都調的是IE7,可惡的是程式對其不可控!可惡的是這個調用的IE7與浏覽器的IE7還不太一樣,我叫它非7非8,有時我在IE7浏覽器裡看到一個樣子,到了黑殼子裡彈出檢測結果是IE7,樣子居然和浏覽器上不一樣,完全(想罵人。。。)不在套路上!而且沒有控制台,任意一個異常,無論是否影響程式,都會彈出一個讨人厭的腳本錯誤的提示框!由于我在浏覽器上調試和開發的,是以一開始并不知道會有這些問題,即便當時我相容到了IE7,到了殼子裡面又是一番烏七八糟的問題!當時每天下班回家躺在床上,我都在懷疑自己的前端之路是不是走進了一條死胡同,完全看不到光,說好的炫酷呢,說好的大前端呢?尼瑪這都什麼鬼?

欣慰的是後端同學在積極研究怎麼切換到webkit的殼子,基于一些不可預知的問題,以及項目催的太緊,到目前為止,我依然天天面對着IE7891011。。。。。不要攔我。。。讓我哭會兒。。。

話說還是要做個堅強的孩子!自己選擇的路,再苦再累也要咬牙走完呀;一方面,相容問題是前端不可避免的問題;另一方面,既然眼下沒有更好的方案,隻有靠自己一步步走穩腳下的路了;

皇天不負苦心人,終于讓我磨出了一個ErrorInspector子產品!

基于以上可惡的讓人懷疑人生的問題,首先解決以下問題:

1、相容到IE7;

2、異常的回報與追蹤(支援跨域);

3、屏蔽掉那個讨人厭的腳本錯誤提示框;

4、要跨終端,比如那個醜的不要的IE殼子,不可調試;

5、錯誤實時上報并通知和展示;

6、一并追蹤與後端互動的錯誤,比如:500、404,把Jquery的ajax拉進來;

7、包裝try_catch,多用try_catch;

由于要相容到IE7,那麼基礎庫用Jquery肯定最好了,加上自己平時造的一些子產品群組件以及Jquery的插件,基本夠開發用了;可憐的我再次與牛逼的React、Angular擦肩而過了;現在以Nodejs的子產品化方式開發,用webpack打包合并,目前感覺還湊合;

最初的想法是,通過window.onerror和try_catch捕獲并上報錯誤到一個獨立的錯誤收集站點,不需要後端配合,自己用Express造一個簡單的站點就是,通過H5的webSocket和Node的Socket.io實時響應上報的錯誤,如果已打開浏覽器端無需重新整理即可收到通知,或者直接發送郵件提示,達到跨終端實時追蹤上報;如果可以的話,在Web上可以做更多工作,比如,圖形化分析和展示,常見錯誤的解決方法的預測和提示,如果是線上收集站點還可以對錯誤極其解決方法做分類收集,供浏覽者參考;總之,face to error,just do it !

因為問題最終上報到我這,是以就不存在浏覽器相容問題了,當然選最好的谷歌了,BSIE!!!;沒做太多優化,第一版錯誤回報展示的頁面大概是這個傻樣子:

當然,圖檔裡是測試的結果,每條展開有更多錯誤的詳情,包括錯誤引發的檔案位址、行号、錯誤類型、浏覽器版本、時間、所在頁面、觸發節點等;實際發現,window.onerror捕獲的錯誤并不總是很詳細,最好是多用包裝好的try_catch去主動上報,才會比較容易定位錯誤源,多用try_catch是個好習慣;因為難免存在跨域的問題,預設使用new Image的方式GET資料,當然,這不是必須的,支援自定義上報位址和上報方法;至于屏蔽掉那個讨人厭的腳本錯誤提示框,其實很簡單,在window.onerror最後return true就是的,但是在谷歌裡就會屏蔽掉控制台輸出的内容,最好線上上環境使用,畢竟本地開發還得在控制台裡調試;

由于Jquery的Ajax使用特别靈活,是以做好全局去捕獲Ajax與後端互動的錯誤;看看Jquery的Ajax常見用法:

// 以GET為例

$.ajax({
    url:'',
    success:function(data){},
    error:function(){}
});
$.get(url,data,function(data){});
$.get(url,data).success(function(data){}).error(function(){});
$.get(url,data).then(function(data){},function(err){});

// ...      

這麼多種用法,每次都去捕獲error事件,然後在裡面上報,肯定是相當不靠譜的;Jquery是很好用的,可以通過設定全局的error事件來捕獲上面各種方式下的錯誤,爽不爽?比如這樣:

$.ajaxSetup({
    timeout:setAjax.$.timeout,
    error: function(xhr){
        setTimeout(function () {
            util.getArgType(setAjax.$.onError)=='function'?setAjax.$.onError(xhr):alert(xhr.status+','+xhr.statusText);
        }, 1);                    
    }
});      

不過這種錯誤一般後端的可能性大些,前端常見的就是這裡的參數沒傳好,引發的後端錯誤,當然可以選擇屏蔽不上報,或簡單的提示個伺服器異常就行了;

ErrorInspector的用法:

1、最好放在各大library的後面,你寫的JS前面,因為架構本身一般不會引發錯誤,主要是監控自己寫的代碼可能存在的未預知的異常;

2、初始化配置:

ErrorInspector.Config={
    url:'http://localhost:2333/ErrorInspector/xiaofeng',   //上報位址
    qs:{
        id:location.host,            //預設以目前域為id
        page:location.host+location.pathname,//錯誤頁面位址
        from:Url,                    //錯誤來源的位址
        row:Number,                  //錯誤行号
        col:Number,                  //錯誤列号
        msg:String,                  //錯誤詳情
        browser:util.Browser,        //浏覽器類型及版本,預設幾大主流浏覽器,後續完善
        time:util.fmtTime(),         //錯誤觸發的時間
        inspector:String,            //上報者window|user|log......
        // ...其他參數
        ext:'hufeng'                 //擴充的參數
    },
    $:{
        timeout:Number,              //Jquery的Ajax逾時設定,會觸發onError
        onError:function(xhr){}      //全局的Jquery的Ajax錯誤捕獲
    },
        submit:function(data){},         //自定義上報方式,回調了上報内容     
    IgnoreFromJSPattern:/reg/ig,     //屏蔽錯誤來源的位址,比如第三方的廣告
    IgnoreMsgPattern:/reg/ig,        //屏蔽上報的消息内容,比如沒太大意義的script.error
    IgnoreBrowserError:0|1           //是否屏蔽控制台,主要屏蔽掉那個IE上讨厭的彈框
}      

ErrorInspector.Config.qs裡的參數一般無需過問,錯誤觸發時會自己收集上報;

3、Tryit(function(report,log){});

包裝好的try_catch,回調的ErrorInspector.report和ErrorInspector.log其實大同小異,除了try_catch裡的上報外,可以用回調值繼續自定義上報;一般用這個函數包裝代碼塊;

4、ErrorInspector.report({name:value});

主動上報;

5、ErrorInspector.log;

模拟簡單的console.log,其實更像alert,可以充當統計代碼用,或許還需改進;

6、後端使用Express和Socket.io,玩過H5的webSocket的同學立馬就懂了,不解釋;

繼續閱讀