Hello,大家好。今天我們來講一下前端出現頻率非常高的一種錯誤:Script error。
Script error.這個錯誤非常的高傲和神祕,爲什麼呢?因爲它出現的時候,不會給你提供任何有關它的線索。正常我們寫的前端代碼報錯的時候,瀏覽器通常拋出錯誤代碼的行列號,以及它的堆棧代碼,這樣我們就可以快速定位到錯誤的位置。而這個錯誤發生的時候,連根毛的線索都沒有提供,有毛的線索嗎 ,一根都沒有。那麼它憑什麼這麼囂張呢?
一、Script error是如何產生的呢?
很多同學看到這個錯誤的時候一臉懵,不知道該咋整,其實他是由第三方js代碼產生了報錯,而瀏覽器存在着同源策略導致它無法像你提供第三方文件的堆棧,除非得到第三方服務器的允許。
最常見的情形是使用CDN託管JS資源。爲了更好地理解,假設以下HTML頁面部署在http://www.webfunny.com域名下:
<!doctype html>
<html>
<head>
<title>這個頁面在這個域名:https://www.webfunny.com</title>
</head>
<body>
<script src="http://www.CDN.com/test.js"></script>
<script>
window.onerror = function (message, url, line, column, error) {
console.log(message, url, line, column, error);
}
// 假如test.js中的代碼發生了報錯
</script>
</body>
假如這個時候,test.js代碼中發生了報錯,這個時候你將會得到 "Script error."。出於安全考慮,瀏覽器會刻意隱藏其他域的JS文件拋出的具體錯誤信息,這樣做可以有效避免敏感信息無意中被不受控制的第三方腳本捕獲。因此,瀏覽器只允許同域下的腳本捕獲具體錯誤信息,而其他腳本只知道發生了一個錯誤,但無法獲知錯誤的具體內容。更多信息,請參見Webkit源碼。
bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& lineNumber, String& sourceURL)
{
KURL targetURL = completeURL(sourceURL);
if (securityOrigin()->canRequest(targetURL))
return false;
errorMessage = "Script error.";
sourceURL = String();
lineNumber = 0;
return true;
}
其實這個並不能算是你們代碼的報錯,所以正常情況下,只要不影響業務,你們是可以睜一隻眼閉一隻眼的(悄悄說的)。但是webfunny作爲一款監控系統,即使不影響業務,我們也得上報並保存下來(這是我們最後的倔強:)
二、Script error這種錯誤怎麼定位呢?
我看很多人都寫了如何去解決script error,但是鮮有人介紹怎麼定位到它。 也許大家可能是忽略了,但是因爲缺乏線索,想定位到它的位置還真是不容易呢。 特別是項目引入了不止一個第三方js文件的時候,你怎麼知道是發生在哪個文件中呢?
其實這就離不開行爲記錄,鏈路追蹤的功能了。通過記錄用戶的行爲軌跡,可以準確的找到Script error的具體時間節點,在那個時間節點你就可以知道調用了什麼方法,從而找到具體位置。
三、Script error這種錯誤怎麼解決呢?
解決方式1:開啓CORS跨域資源共享
爲了跨域捕獲JavaScript異常,可執行以下兩個步驟:
1. 添加crossorigin="anonymous"
屬性。此步驟的作用是告知瀏覽器以匿名方式獲取目標腳本。這意味着請求腳本時不會向服務端發送潛在的用戶身份信息(例如Cookies、HTTP證書等)。
<script src="http://www.CDN/test.js" crossorigin="anonymous"></script>
2. 添加跨域HTTP響應頭。
Access-Control-Allow-Origin: * // 或者業務域名
完成上述兩步之後,即可通過window.onerror
捕獲跨域腳本的報錯信息。回到之前的案例,頁面重新運行後,捕獲到的結果是:
解決方式2:利用try catch重新捕獲
已添加 crossorigin 依然有 script error。由於部分瀏覽器對crossorigin屬性不支持,又或者我們無法往HTTP請求響應頭裏面添加跨域屬性,因此依然可能產生script error。
這時還可以通過try catch獲取頁面報錯信息,將JS錯誤重新拋出或者上報。
try {
run(); // 調用test.js中定義的run方法
} catch (e) {
console.log(e);
throw e;
}
最後、Script error.其實並不是什麼嚴重的問題,很少遇到這種錯誤會影響到正常的業務,一般第三方都會做好兼容處理。 但是呢,它會讓人看着心煩,所以在確認對業務沒有影響的時候,可考慮把它過濾掉。這樣就不會影響線上的錯誤率了(以防背鍋挨批,哈哈)
參考文檔:https://help.aliyun.com/zh/arms/browser-monitoring/support/causes-and-solutions-for-script-errors