Ho bisogno di due istanze del servizio http di AngularJS $ o cosa?

Voglio aggiungere un intercettore di risposta al mio servizio $ http per scopi di gestione degli errori. La logica di intercettazione include messaggi di errore di invio al server utilizzando $ http nel caso sia necessario, MA non voglio inviare messaggi di errori al server sui messaggi di errore, voglio dire, voglio disabilitare il mio intercettore mentre invio un messaggio di errore al server.

La mia idea era di creare un servizio chiamato ‘remote_log’ e di inserire tutto il codice necessario per inviare un errore al server. Ovviamente quel servizio utilizzerà il servizio $ http e lo avrà nella sua lista delle dipendenze.

Quindi aggiungere come dipendenza dell’intercettore al servizio ‘remote_log’ e utilizzare il ‘remote_log’ all’interno dell’intercettore quando è necessario inviare errori al server. I problemi sono che:

Gli intercettori devono essere definiti utilizzando $ httpProvider quando il servizio $ http non è ancora istanziato / accessibile, quindi, all’interno del codice dell’intercettore non può essere una dipendenza dal servizio $ http perché si verifica un errore di “dipendenza circolare”.

Penso che la mia unica opzione sia creare un’istanza separata del servizio $ http nel mio ‘remote_log’, un’istanza che non usa la configurazione $ httpProvider che ho impostato durante la creazione dell’intercettore. La mia domanda è: come posso farlo? Altre idee?

1. Problema di dipendenza circolare.

Quindi, perché appare l’errore? Ecco una rapida panoramica del processo:

  1. $ http è richiesto.
  2. $ httpProvider è invitato a costruirlo.
  3. Durante la costruzione si registra l’intercettore, che richiede il servizio $ http non ancora esistente.
  4. Ottiene l’errore “Dipendenza circolare”.

Prima soluzione

Crea la tua dipendenza usando angular.injector (). Nota che creerai un altro servizio $ http, indipendente dalla tua app.

$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. }); } }; }); 

Seconda soluzione (migliore).

Iniettare $ injector nel proprio intercettore e utilizzarlo per recuperare le dipendenze dopo l’inizializzazione $ http, proprio nel momento in cui ne avete bisogno. Queste dipendenze sono servizi registrati della tua app e non verranno creati di nuovo!

 $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. Problema di prevenzione dell’intercettazione.

Se si utilizza la seconda soluzione, ci sono in realtà due problemi:

  1. Se si utilizza il servizio $ http all’interno dell’intercettatore, si possono finire intercettazioni infinite: si invia una richiesta, l’intercettore lo intercetta, ne invia un altro, ne prende un altro, invia di nuovo e così via.
  2. A volte vuoi solo impedire che la richiesta venga intercettata.

Il parametro ‘config’ del servizio $ http è solo un object. È ansible creare una convenzione, fornendo parametri personalizzati e riconoscendoli nei propri intercettori.

Ad esempio, aggiungiamo la proprietà “nointercept” alla configurazione e proviamo a duplicare ogni richiesta dell’utente. Questa è un’applicazione stupida, ma un utile esempio per capire il comportamento:

 $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; } } }; }); 

Avendo il test per la proprietà in intercettore, è ansible impedire l’intercettazione in controller e servizi:

 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) { // ... }); }); 

Ho usato ciò che è descritto nella risposta, ma ho usato la syntax con una fabbrica perché con la funzione anonima non ha funzionato, non so davvero perché:

 (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));