Help us understand the problem. What is going on with this article?

Angularでエラーハンドリングする2つの方法

More than 3 years have passed since last update.

エラーハンドリングしよう!

はじめに

クライアント側(ブラウザ)で発生したエラー情報をWebサーバ側に渡してログ書いたり画面遷移させたり何らかの処理をさせたいときに、どうやったらエラー情報を取得できるか、またどうやったら独自処理を実装できるのか調べました。

※TypeScriptで実装しています。

$exceptionHandler

AngularJSでは例外が投げられた場合、$exceptionHandlerというサービスに処理が委譲され、$logサービスでブラウザコンソールにログが出力されます(※1)。

エラー処理を独自で実装したい場合の2つの方法です。

  • $exceptionHandlerを上書き(override)する方法
    • 公式サイトではこちらの例が紹介されています。
  • $exceptionHandlerを装飾(decorator)する方法
    • 海外のサイトではこちらが多い印象でした。

注意事項

  • 上書き(override)するともともと$exceptionHandlerがデフォルトで持っている処理(※1)が消えてしまうため、残したい場合は同等の処理を記述するか装飾(decorator)で対応する必要があります。

  • 公式サイトに書いてあるのですが、$exceptionHandlerはAngular監視外のエラーは検知できないようなので、try-catchでエラーを検知したりerrorオブジェクトを生成して自分でthrowする必要があります(⇒余談①:throw Error)。

実装方法

上書き(override)

公式

The example below will overwrite the default $exceptionHandler in order to (a) log uncaught errors to the backend for later inspection by the developers and (b) to use $log.warn() instead of $log.error().

overrideExample.js
angular.
  module('exceptionOverwrite', []).
  factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) {
    return function myExceptionHandler(exception, cause) {
      logErrorsToBackend(exception, cause);
      $log.warn(exception, cause);
    };
  }]);

引用元:AngularJS: API: $exceptionHandler

ちょっと内容が変わっていますがTypeScriptでシンプルにかくとこんな感じでしょうか。

overrideExample.ts
angular.
    module('exceptionOverwrite', []).
    factory('$exceptionHandler', () => {
        return (exception: Error, cause: string) => {
            //エラー発生時に実行したい処理
            alert(exception.message);//アラートで表示
            console.warn(exception.message);//コンソールで表示
        };
    })

buildinsiderのサイトでもサンプルを見ることができます。

装飾(decorator)

一例です。

decoratorExample.ts
angular.
    module('exceptionOverwrite', [])
    .config(['$provide', ($provide: ng.auto.IProvideService) => {
        $provide.decorator('$exceptionHandler',
            ['$delegate', extendExceptionHandler]);
    }]);

function extendExceptionHandler($delegate: ng.IExceptionHandlerService): ng.IExceptionHandlerService{
    return (exception: Error, cause: string) => {
        $delegate(exception, cause);
        //エラー発生時に実行したい処理
        alert(exception.message);//アラートで表示
        console.warn(exception.message);//コンソールで表示
    };
}

余談①:throw Error

任意の場所でエラーを発生させたいとき

error.ts
var error: Error = {
    name: "hogehoge",
    message: "エラーが発生しました。"
};
throw error;

余談②:Error: $injector:cdep

httpサービス使おうとしたときに循環参照発生したので回避策(extendExceptionHandler)

hoge.ts
function extendExceptionHandler($delegate: ng.IExceptionHandlerService): ng.IExceptionHandlerService{
    return (exception: Error, cause: string) => {
        $delegate(exception, cause);

        var $injector = angular.injector(['ng']);
        var $http:ng.IHttpService = $injector.get('$http');
        $http.post('hoge/hoge', exception);
    };
}

参考

AngularJS: API: $exceptionHandler
AngularJS Exception Logging Made Simple 
Github:exception-handler.provider.ts
stackoverflow:how-to-override-exceptionhandler-implementation

gunosy
情報キュレーションサービス「グノシー」や「ニュースパス」の開発・運営を通じて、情報を世界の人に最適に届けていきます。
http://gunosy.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away