22

エラー処理の目的で、$http サービスに応答インターセプターを追加したいと考えています。インターセプターのロジックには、必要に応じて $http を使用してサーバーにエラー メッセージを送信する機能が含まれていますが、エラー メッセージについてサーバーにエラー メッセージを送信したくありません。つまり、エラー メッセージをサーバーに送信している間はインターセプターを無効にしたいということです。

私の考えは、「remote_log」という名前のサービスを作成し、サーバーにエラーを送信するために必要なすべてのコードをその中に入れることでした。もちろん、そのサービスは $http サービスを使用し、それを依存リストに含めます。

次に、インターセプターの依存関係として「remote_log」サービスに追加し、必要に応じてインターセプター内で「remote_log」を使用してサーバーにエラーを送信します。問題は次のとおりです。

$http サービスがまだインスタンス化されていない/アクセスできない場合、インターセプターは $httpProvider を使用して定義する必要があります。そのため、「循環依存」エラーが発生するため、インターセプター コード内で $http サービスに依存することはできません。

私の唯一のオプションは、「remote_log」内に $http サービスの別のインスタンスを作成することだと思います。これは、インターセプターの作成中に設定した $httpProvider 構成を使用しないインスタンスです。私の質問は次のとおりです。どうすればそれを行うことができますか? 他のアイデアはありますか?

4

2 に答える 2

56

1. 循環依存の問題。

では、なぜエラーが表示されるのでしょうか。プロセスの概要は次のとおりです。

  1. $http サービスが要求されます。
  2. $httpProvider はそれを構築するよう求められます。
  3. 構築中に、まだ存在しない $http サービスを要求するインターセプターを登録します。
  4. 「循環依存」エラーが発生します。


最初の解決策。

angular.injector() を使用して依存関係を作成します。アプリとは別に、別の $http サービスを作成することに注意してください。

$httpProvider.interceptors.push(function($q) {
    $injector = angular.injector();
    return {
        response: function(response) {
            $injector.invoke(function($http) {
                // This is the exterior $http service!
                // This interceptor will not affect it.
            });
        }
    };
});


2番目の解決策(より良い)。

インターセプターに $injector を注入し、それを使用して、$http の初期化後に必要なときに依存関係を取得します。これらの依存関係はアプリの登録済みサービスであり、新たに作成されることはありません!

$httpProvider.interceptors.push(function($q, $injector) {
    return {
        response: function(response) {
            $injector.invoke(function($http, someService) {
                // $http is already constructed at the time and you may
                // use it, just as any other service registered in your
                // app module and modules on which app depends on.
            });
        }
    };
});


2.傍受防止の問題。

2 番目の解決策を使用する場合、実際には 2 つの問題があります。

  1. インターセプター内で $http サービスを使用すると、無限のインターセプトが発生する可能性があります。リクエストを送信し、インターセプターがそれをキャッチし、別のものを送信し、別のものをキャッチし、再度送信するなどです。
  2. リクエストが傍受されるのを防ぎたい場合があります。

$http サービスの「config」パラメータは単なるオブジェクトです。カスタムパラメーターを提供し、インターセプターでそれらを認識する規則を作成できます。

たとえば、「nointercept」プロパティを構成に追加して、すべてのユーザー リクエストを複製してみましょう。これはばかげたアプリケーションですが、動作を理解するのに役立つ例です:

$httpProvider.interceptors.push(function($q, $injector) {
    return {
        response: function(response) {
            if (response.config.nointercept) {
                return $q.when(response); // let it pass
            } else {
                var defer = $q.defer();
                $injector.invoke(function($http) {
                    // This modification prevents interception:
                    response.config.nointercept = true;
                    // Reuse modified config and send the same request again:
                    $http(response.config)
                        .then(function(resp) { defer.resolve(resp); },
                              function(resp) { defer.reject(resp); });
                });
                return defer.promise;
            }
        }
    };
});

インターセプターでプロパティをテストすると、コントローラーとサービスでのインターセプトを防ぐことができます。

app.controller('myController', function($http) {
    // The second parameter is actually 'config', see API docs.
    // This query will not be duplicated by the interceptor.
    $http.get('/foo/bar', {nointercept: true})
        .success(function(data) {
            // ...
        });

});
于 2013-11-13T13:02:58.843 に答える
0

回答に記載されているものを使用しましたが、匿名関数では機能しなかったため、ファクトリで構文を使用しました。理由はよくわかりません。

(function(angular){
    angular.module('app', [])
    .config([
        '$httpProvider',
        function($httpProvider) {
                $httpProvider.interceptors.push('Interceptor');
        } 
    ])
    .factory('Interceptor', [
        '$injector',
        InterceptorFactory
    ]);

    function InterceptorFactory($injector){

        return {
            request: function(config) {             
                var ServiceWithHttp = $injector.get('ServiceWithHttp');
                // Use ServiceWithHttp
                return config;
            }
        };
    }

}(window.angular));
于 2015-08-03T10:32:39.617 に答える