【转】window.onerror跨域问题
What the heck is "Script error"?
Ben Vinegar/ May 17, 2016

If you’ve done any work with the JavaScript onerror event before, you’ve probably come across the following:
"Script error."
“Script error” is what browsers send to the onerror callback when an error originates from a JavaScript file served from a different origin (different domain, port, or protocol). It’s painful because even though there’s an error occurring, you don’t know what the error is, nor from which code it’s originating. And that’s the whole purpose of window.onerror – getting insight into uncaught errors in your application.
The cause: cross-origin scripts
To better understand what’s going on, consider the following example HTML document, hypothetically served from http://example.com/test:
<!doctype html>
<html>
<head>
<title>example.com/test</title>
</head>
<body>
<script src="http://another-domain.com/app.js"></script>
<script>
window.onerror = function (message, url, line, column, error) {
console.log(message, url, line, column, error);
}
foo(); // call function declared in app.js
</script>
</body>
</html>
Here’s the contents of http://another-domain.com/app.js. It declares a single function, foo , whose invocation will always throw a ReferenceError.
// another-domain.com/app.js
function foo() {
bar(); // ReferenceError: bar is not a function
}
When this document is loaded in the browser and JavaScript is executed, the following is output to the console (logged via the window.onerror callback):
"Script error.", "", 0, 0, undefined
This isn’t a JavaScript bug – browsers intentionally hide errors originating from script files from different origins for security reasons. It’s to avoid a script unintentionally leaking potentially sensitive information to an onerror callback that it doesn’t control. For this reason, browsers only give window.onerror insight into errors originating from the same domain. All we know is that an error occurred – nothing else!
I’m not a bad person, really!
Despite browsers’ good intentions, there are some really good reasons why you want insight into errors thrown from scripts served from different origins:
- Your application JavaScript files are served from a different hostname, e.g. static.sentry.io/app.js.
- You are using libraries served from a community CDN, like cdnjs or Google’s Hosted Libraries.
- You’re working with a commercial 3rd-party JavaScript library, that is only served from external servers.
But don’t worry – getting insight into a JavaScript error served by these files just needs a few simple tweaks.
The fix: CORS attributes and headers
In order to get visibility into a JavaScript exception thrown from scripts originating from different origins, you must do two things.
1) Add a crossorigin=”anonymous” script attribute
<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>
This tells the browser that the the target file should be fetched “anonymously”. This means that no potentially user-identifying information like cookies or HTTP credentials will be transmitted by the browser to the server when requesting this file.
2) Add a Cross Origin HTTP header
Access-Control-Allow-Origin: *
CORS is short for “Cross Origin Resource Sharing”, and it’s a set of APIs (mostly HTTP headers) that dictate how files ought to be downloaded and served across origins.
By setting Access-Control-Allow-Origin: *, the server is indicating to browsers that any origin can fetch this file. Alternatively, you can restrict it to only a known origin you control, e.g.
Access-Control-Allow-Origin: https://www.example.com
Note: most community CDNs properly set an Access-Control-Allow-Origin header.
$ curl --head https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.js | \
grep -i "access-control-allow-origin"
Access-Control-Allow-Origin: *
Once both of these steps have been made, any errors triggered by this script will report to window.onerror just like any regular same-domain script. So instead of “Script error”, the onerror example from the beginning will yield:
"ReferenceError: bar is not defined", "http://another-domain.com/app.js", 2, 1, [Object Error]
Boom! You’re done – ”Script error” will plague you and your team no more.
An alternative solution: try/catch
Sometimes, we’re not always in a position to be able to adjust the HTTP headers of scripts our web application is consuming. In those situations, there is an alternative approach: using try/catch.
Consider the original example again, this time with try/catch:
<!-- note: crossorigin="anonymous" intentionally absent -->
<script src="http://another-domain.com/app.js"></script>
<script>
window.onerror = function (message, url, line, column, error) {
console.log(message, url, line, column, error);
}
try {
foo(); // call function declared in app.js
} catch (e) {
console.log(e);
throw e; // intentionally re-throw (caught by window.onerror)
}
</script>
For posterity, some-domain.com/app.js once again looks like this:
// another-domain.com/app.js
function foo() {
bar(); // ReferenceError: bar is not a function
}
Running the example HTML will output the following 2 entries to the console:
=> ReferenceError: bar is not defined
at foo (http://another-domain.com/b.js:2:3)
at http://example.com/test/:15:3
=> "Script error.", "", 0, 0, undefined
The first console statement – from try/catch – managed to get an error object complete with type, message, and stack trace, including file names and line numbers. The second console statement from window.onerror, once again, can only output “Script error.”
Now, does this mean you need to try/catch all of your code? Probably not – if you can easily change your HTML and specify CORS headers on your CDNs, it is preferable to do so and stick to window.onerror.
But, if you don’t control those resources, using try/catch to wrap 3rd-party code is a surefire (albeit tedious) way to get insight into errors thrown by cross-origin scripts.
Note: by default, Raven.js – Sentry’s JavaScript SDK – carefully instruments built-in methods to try to automatically wrap your code in try/catch blocks. It does this to attempt to capture error messages and stack traces from all your scripts, regardless of which origin they’re served from. It’s still recommended to set CORS attributes and headers if possible.
If this blog post helped you out, and you’d like to learn more about window.onerror, you should also check out our other blog post: Capture and report JavaScript errors with window.onerror.
【转】window.onerror跨域问题的更多相关文章
- window.name 跨域
跨域的由来 JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象.但是我们常常会遇到无法避免跨域的情况,如普通文章站点(article.xxx.com)需要评论,而评论站点却在chea ...
- JS window.name跨域封装
JS window.name 跨域封装 function CrossDomainName(target, agent, callback, security) { if (typeof target ...
- window.name跨域
window.name? 每一个页面都有一个自己的window,而window.name是window的名字. window.name跨域原理 window对象有个name属性,该属性有个特征:即在一 ...
- window.returnValue跨域传值问题[转]
主页面用window.showModalDialog的时候,如果直接打开其它系统的页面,这时候别人的页面在window.returnValue=1;这样返回值的时候,主页面是取不到返回值的,原因就是因 ...
- HTML5 window/iframe跨域传递消息 API
原文地址:HTML5′s window.postMessage API 在线示例:Using HTML5's window.postMessage(请打开控制台看日志) 原文日期: 2010年09月0 ...
- (二)文档请求不同源之window.name跨域
一.基本原理 window.name不是一个普通的全局变量,而是当前窗口的名字.这里要注意的是每个iframe都有包裹它的window,而这个window 是top window的子窗口,而它自然也有 ...
- (二)文档请求不同源之window.postMessage跨域
一.基本原理 HTML5为了解决跨域,引入了跨文档通信API(Cross-document messaging).这个API为window对象新增了一个window.postMessage方法,允许跨 ...
- window.name跨域实现
参考:window.name实现的跨域数据传输 有三个页面: a.com/app.html:应用页面. a.com/proxy.html:代理文件,一般是一个没有任何内容的html文件,需要和应用页面 ...
- window.name 跨域数据传输
通过window.name可以实现跨域数据传输. 要解决的功能: www.a.com/a.html 需要获取到 www.b.com/b.html页面内容的数据 需要3个页面 www.a.com/a. ...
随机推荐
- 《11招玩转网络安全》之第三招:Web暴力破解-Low级别
Docker中启动LocalDVWA容器,准备DVWA环境.在浏览器地址栏输入http://127.0.0.1,中打开DVWA靶机.自动跳转到了http://127.0.0.1/login.php登录 ...
- 题解 P1801 【黑匣子_NOI导刊2010提高(06)】
蒟蒻来发题解了.我仔细看了一下其他题解,各位巨佬用了堆,红黑树,splay,treap之类的强大算法,表示蒟蒻的我只会口胡这些算法,所以我决定用一种极其易理解的算法————fhq treap,作为tr ...
- 【ShaderToy】画一个球体
嗯,其实渲染球体,可以看做就是一个2d圆形图案+渲染光泽的函数. 定义球体结构——半径,球心坐标 struct Sphere { vec3 center; float radius; };edzx- ...
- <发条游戏设计>粗翻——第一部分 理论(一)
段落1 游戏 游戏设计定义 相对而言,游戏设计是一个新的学科,专业的作曲家.画家.作家.建筑师已经至少存在了500多年,然而游戏设计师只在最近50年才被特分出来单作一类.然而这个类别仅仅在最近20-2 ...
- MyRolan (快速启动小工具)
类似 Rolan的快速启动工具. 启动后隐藏,当鼠标移至左上角时,窗口显示,点击项目可运行程序. GitHub地址: MyRolan . #if defined(UNICODE) && ...
- JVM调优的几种策略
一.JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老代) 永久代(Perm) 其中New和Tenured属于堆内存,堆内存会从J ...
- L1-Day13
1.Being late is an unforgivable sin here.[我的翻译]在北京,迟到是不可饶恕的罪名.[标准答案]在这里迟到是不可原谅的.[对比分析]对自己的也是醉醉的了,Bei ...
- MongoDB代码——Python篇
需要安装的库:pymongo 一.添加文档 from pymongo import MongoClient # 连接服务器 conn = MongoClient("localhost&quo ...
- Image 上传下载Api
1.配置 "UploadConfig": { // 自定义存放位置,无需放到站点内部 "Path": "C:\\Users\\kxy\\Desktop ...
- C++11 double转化为string
C++11转化double为string是一件很容易的事情. 方法: 1:使用C中的sprintf函数,这里就不说了. 2:使用std::ostringstream.这个与std::cout是一样的. ...