エラーハンドリングしよう!
はじめに
クライアント側(ブラウザ)で発生したエラー情報を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()
.
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でシンプルにかくとこんな感じでしょうか。
angular.
module('exceptionOverwrite', []).
factory('$exceptionHandler', () => {
return (exception: Error, cause: string) => {
//エラー発生時に実行したい処理
alert(exception.message);//アラートで表示
console.warn(exception.message);//コンソールで表示
};
})
buildinsiderのサイトでもサンプルを見ることができます。
装飾(decorator)
一例です。
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
任意の場所でエラーを発生させたいとき
var error: Error = {
name: "hogehoge",
message: "エラーが発生しました。"
};
throw error;
余談②:Error: $injector:cdep
httpサービス使おうとしたときに循環参照発生したので回避策(extendExceptionHandler)
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