原文地址javascript
在前端開發工做中,除了項目開發保質保量上線之外,項目的數據監控也應該配套起來,確保線上的正常運轉。如上報 pv 監控項目是否正常運轉;測速上報反應項目質量;腳本錯誤監控做爲監控中重要一環,當頁面發生報錯的時候,經過上報錯誤信息,能及時發現存在問題,修復優化、減小損失。html
本文基於在手Q家校羣前端腳本錯誤量優化的方案,致力於打造極致的腳本錯誤優化。前端
做爲首篇,主要講解基礎的腳本錯誤監控和上報方式,以及常會遇到的 Script error. 的產生緣由和處理方法。java
腳本錯誤主要有兩類:語法錯誤、運行時錯誤。
監控的方式主要有兩種:try-catch、window.onerror。git
try {
test // <- throw error
} catch(e){
console.log('運行時錯誤信息 ↙');
console.log(e);
}複製代碼
經過給代碼塊進行 try-catch 包裝,當代碼塊出錯時 catch 將能捕獲到錯誤信息,頁面也將繼續執行。github
當發生語法錯誤或異步錯誤時,則沒法正常捕捉。web
try {
function empty() // <- throw error 語法錯誤 } catch(e){
console.log('語法錯誤信息 ↙');
console.log(e);
}複製代碼
沒法捕捉錯誤跨域
try {
setTimeout(function() {
test // <- throw error 異步錯誤
},0)
} catch(e){
console.log('異步錯誤信息 ↙');
console.log(e);
}複製代碼
沒法捕捉錯誤瀏覽器
語法錯誤沒法在 try-catch 中進行捕抓、而異步報錯則能夠經過爲異步函數塊再包裝一層 try-catch,增長標識信息來配合定位,能夠用工具來進行處理,這裏不展開。緩存
/** * @param {String} msg 錯誤信息 * @param {String} url 出錯文件 * @param {Number} row 行號 * @param {Number} col 列號 * @param {Object} error 錯誤詳細信息 */
window.onerror = function (msg, url, row, col, error) {
console.log('onerror 錯誤信息 ↙');
console.log({
msg, url, row, col, error
})
};
test // <- throw error複製代碼
window.onerror 能捕捉到當前頁面的語法錯誤或運行時報錯,是十分強大的。
那麼try-catch 是否再也不須要呢?其實並非。
在使用過程當中的體會:onerror 主要用來捕獲預料以外的錯誤,而 try-catch 則能夠用在預知狀況下監控特定錯誤,兩種形式結合使用更加高效。
監控錯誤拿到了報錯信息,接下來則是將捕抓的錯誤信息發送到信息收集平臺上,發送的形式主要有兩種:
function report(msg, level) {
var reportUrl = "http://localhost:8055/report";
new Image().src = reportUrl + '?msg=' + msg;
}複製代碼
監控報錯,並將捕捉到的錯誤信息上報給數據收集平臺,以下圖
有了監控了後,就能夠在收集平臺上進行查看腳本錯誤量的日誌統計。
發現佔據榜首的錯誤信息 「Script error.」 具備很是高的比例,沒有無具體的錯誤信息,沒法定位問題,而這是怎麼產生的呢?
翻看在 webkit 的源碼能夠看到 「Script error.」 是瀏覽器在同源策略限制下所產生的。瀏覽器出於安全上的考慮,當頁面引用的非同域的外部腳本中拋出了異常,此時本頁面無權限得到這個異常詳情, 將輸出 Script error 的錯誤信息。
Script error 來自同源策略的影響,那麼解決的方案之一是進行資源的同源化,另外也能夠利用跨源資源共享機制( CORS )。
以上兩種方式可以簡單直接地解決問題,但也可能帶來其餘影響,如內聯資源很差利用文件緩存,同域沒法充分利用cdn優點等等。
跨源資源共享 ( CORS )機制讓Web應用服務器能支持跨站訪問控制,從而可以安全地跨站數據傳輸。主要是經過給請求帶上特定頭信息,服務器實現了CORS接口,就能夠跨源通訊,從而可以看到具體報錯信息。
<script src="http://127.0.0.1:8077/main.js" crossorigin></script>複製代碼
增長 crossorigin 屬性後,瀏覽器將自動在請求頭中添加一個 Origin 字段,發起一個 跨來源資源共享 請求。Origin 向服務端代表了請求來源,服務端將根據來源判斷是否正常響應。
Access-Control-Allow-Origin: * 表示經過該跨域請求,且該資源能夠被任意站點跨站訪問。而當該資源僅容許來自 http://127.0.0.1:8066 的跨站請求,其它站點都不能跨站訪問時,將能夠返回:
Access-Control-Allow-Origin:http://127.0.0.1:8066複製代碼
Vary 字段的做用在於爲緩存服務器提供緩存規則及緩存篩選的依據。當增長 Vary:Origin 響應頭後,緩存服務器將會按照 Origin 字段的內容,緩存不一樣版本,在請求響應時根據請求頭中的 Origin 決定是否可以使用緩存響應。
舉例 · 不加 Vary 將存在錯誤命中緩存的問題
上圖中,第一個請求(Origin: 127.0.0.1:8066)響應被瀏覽器緩存了,當第二個請求(Origin: 127.0.0.1:8888)發起,被錯誤命中了前一個請求的緩存,收到了 Access-Control-Allow-Origin:http://127.0.0.1:8066 的響應時,將致使資源加載失敗。
因此當 Access-Control-Allow-Origin 不是返回爲 * 時,須要加上 Vary 返回頭來避免引緩存致使的權限問題。
跨域腳本報錯產生 Script error. 經過以上方式進行處理後將可以捕獲到具體的報錯信息了。在 NodeJS 的實現中主要經過添加如下代碼:
app.use(function *(next){
// 拿到請求頭中的 Origin
var requestOrigin = this.get('Origin');
if (!requestOrigin) { // 不存在則忽略
return yield next;
}
// 設置 Access-Control-Allow-Origin: Origin
this.set('Access-Control-Allow-Origin', requestOrigin);
// 設置 Vary: Origin
this.vary('Origin');
return yield next;
});複製代碼
以上爲本文全部內容,兄弟篇:( coming soon.. )