我找到了多种方法:
1.) 数据 URI
我从数据 URI 方法开始,这种方法没有得到广泛支持,但仍然比什么都没有:
function report(e){
console.log(e.stack);
}
window.onload = function (){
var s = document.createElement("script");
s.setAttribute("src", "data:text/html,try {throw new Error;}catch(e){report(e);}");
var body = document.getElementsByTagName("body")[0];
body.appendChild(s);
}
它可以在最近的主流桌面浏览器中使用,除了 IE,它不允许使用脚本标签的数据 URI。它记录以下堆栈:
Error
at data:text/html,try {throw new Error;}catch(e){report(e);}:1:12
2.) IFrame
后来我想了想,如果这适用于数据 URI,那么它可能也适用于 iframe,所以我想出了这个:
function report(e){
console.log(e.stack);
}
window.onload = function (){
var i = document.createElement("iframe");
i.setAttribute("style", "display:none");
var body = document.getElementsByTagName("body")[0];
body.appendChild(i);
var idoc = i.contentDocument || i.contentWindow.document;
var ibody = idoc.getElementsByTagName("body")[0];
var s = document.createElement("script");
s.innerHTML="try {throw new Error;}catch(e){parent.report(e);}";
ibody.appendChild(s);
}
它记录以下堆栈:
FF:
@about:blank:1:12
window.onload@file:///C:/Users/inf3rno/Downloads/x.html:18:2
Chrome 和 Opera:
Error
at <anonymous>:1:12
IE11
Error
at Global code (Unknown script code:1:6)
at window.onload (file:///C:/Users/inf3rno/Downloads/x.html:17:2)
我们可以简单地通过添加一个函数调用来添加另一个框架:
s.innerHTML="function a(){\ntry {\nthrow new Error;\n}catch(e){\nparent.report(e);\n}\n};\n a();";
在 IE 中记录以下内容:
Error
at a (Unknown script code:3:1)
at Global code (Unknown script code:8:2)
at window.onload (file:///C:/Users/inf3rno/Downloads/x.html:19:2)
所以我们可以将at a (Unknown script code:3:1)与在父窗口中调用的类似函数进行比较:at a (file:///C:/Users/inf3rno/Downloads/x.html:13:1),并且相对容易找到路径。
3.) 评估
使用 eval 是一种有趣的方法。它在 IE 中提供类似于 at a (eval code:3:1) 的内容,而在其他浏览器和节点中,它提供了一个复杂的嵌套位置:at a (eval at window.onload (x.html:21), <anonymous>:3:7) 或 at a (eval at <anonymous> (repl:1:1), <anonymous>:1:20)。我认为这是最好的方法,因为它不需要 DOM,即使在严格模式下也可以在每个 js 环境中使用。