window.onerrorでエラー内容が取れない時の対応

  • 48
    いいね
  • 0
    コメント

window.onerrorについて

window.onerror = function (msg, file, line, column, err) {
    /*
    msg: error message
    file: file path
    line: row number
    column: column number
    err: error object
    */ 
    alert(msg + file + ':' + line);
};

window.onerrorに関数を設定しておくと、処理中catchされてないエラー、つまりUncaughtErrorの情報をここで取得することが出来ます。

"Script error. line: 0"

window.onerror = function (msg, file, line, column, err) {
    console.error(msg + file + ':' + line);
};

throw new Error('test');

この時、msgには"Uncaught Error test"が渡ることが期待されますが、何故か"Script error."が常に渡ってくる場合があります。コンソールのログには出力されますが、エラーログを送信するなどの処理を書いている場合、原因を特定できないため非常に困ります。

原因と対策

これはブラウザのSame-Origin Policyによるもので、別ドメインのjsファイルをロードした時に起こります。
解決するためにはCORSを適切に設定する必要があります

  • Access-Control-Allow-Originをヘッダに設定

    サーバー側の設定でヘッダーに

    Access-Control-Allow-Origin: [許可するURI]
    

    を追加します。全てのアクセス元に対して許可する場合は*を指定します。

  • crossorigin属性を設定

    クライアント側でscriptタグに以下のようにcrossorigin属性を追加します。

    <script type="text/javascript" src="hoge.js" crossorigin="anonymous"></script>
    

requirejsの対応

require.jsを利用してロードする場合、前述したような対応はとれません。
require.loadをoverrideする方法もありますが、あまり選びたくない方法です。
そこで調べていると既にissueがあがっていました。

https://github.com/jrburke/requirejs/issues/687

require.createNodeをoverrideして属性を追加できるようにしてくれたようです。

元のコード
require.createNode = function (config, moduleName, url) {
    var node = config.xhtml ?
    document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
    document.createElement('script');

    node.type = config.scriptType || 'text/javascript';
    node.charset = 'utf-8';
    node.async = true;
    return node;
};
crossorigin属性を追加
require.createNode = function (config, moduleName, url) {
    var node = config.xhtml ?
    document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
    document.createElement('script');

    node.type = config.scriptType || 'text/javascript';
    node.charset = 'utf-8';
    node.async = true;
    node.setAttribute('crossorigin', 'anonymous');
    return node;
};

これでrequirejsでロードする場合にも対応出来ました。