【转】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. ...
随机推荐
- H5_0002:微信分享设置
1,非公众号的链接,设置分享的预览图片. 先打开页面,在收藏页面,最后在收藏界面长按 “转发” ,即可在链接上出现预览图片.
- python的socket解析
1.实现一对一的进行沟通交流 (1).服务端代码如下: import socket server = socket.socket() server.bind(("localhost" ...
- Axis2 WebService客户端Axis2调用
第一RPC方式,不生成客户端代码 第二,document方式,不生成客户端代码 第三,用wsdl2java工具,生成客户端方式调用 package samples.quickstart.client; ...
- 将应用部署到Tomcat根目录的方法
将应用部署到Tomcat根目录的目的是可以通过“http://[ip]:[port]”直接访问应用,而不是使用“http://[ip]:[port]/[appName]”上下文路径进行访问. 方法 ...
- node-RED
node-RED提供了一个基于浏览器的编辑器,可以轻松地使用调色板中的广泛节点将流连接在一起,这些节点可以通过单击部署到其运行时.使用Node-RED,开发人员将输入/输出和处理节点连接起来,创建流程 ...
- Python 数据分析4
本章概要 数据加载.存储与文件格式 数据加载.存储与文件格式 读取文本格式数据 read_csv 默认是按照逗号分割,也可设定其他分割符 df = pd.read_csv('file', sep='| ...
- 开源mall学习
https://github.com/macrozheng/mall 学习知识点 1.Spring Security 2.@Aspect 3.logstash 4. es crud templete ...
- [经验交流] kubeadm 安装 kubernetes 一年过期的解决办法
kubeadm 是 kubernetes 提供的一个初始化集群的工具,使用起来非常方便.但是它创建的apiserver.controller-manager等证书默认只有一年的有效期,同时kubele ...
- 利用C# 窗体设计 写一个抽奖游戏
老师布置了一个任务,要求我们做一个抽奖游戏,以下是我个人制作的一个作品与写项目的过程. 我们用到了8个pictureBox控件和一个button,设置好大小,并且编排成一个九宫个形状 添加窗体的背景图 ...
- MySQL1:客户端/服务器架构
一.MySQL的客户端/服务器架构 前言 之前对MySQL的认知只限于会写些SQL,本篇算是笔记,记录和整理下自己对MySQL不熟悉的地方. 大致逻辑: MySQL的服务器程序直接和我们存储的数据打交 ...