Ce que j'essaie de réaliser
J'aimerais passer à un certain état (connexion) au cas où une demande $ http renvoie une erreur 401. J'ai donc créé un intercepteur $ http.
Le problème
Lorsque j'essaie d'insérer '$ state' dans l'intercepteur, j'obtiens une dépendance circulaire. Pourquoi et comment je le répare?
Code
//Inside Config function
var interceptor = ['$location', '$q', '$state', function($location, $q, $state) {
function success(response) {
return response;
}
function error(response) {
if(response.status === 401) {
$state.transitionTo('public.login');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
return function(promise) {
return promise.then(success, error);
}
}];
$httpProvider.responseInterceptors.Push(interceptor);
Utilisez le $injector
service pour obtenir une référence au $state
un service.
var interceptor = ['$location', '$q', '$injector', function($location, $q, $injector) {
function success(response) {
return response;
}
function error(response) {
if(response.status === 401) {
$injector.get('$state').transitionTo('public.login');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
return function(promise) {
return promise.then(success, error);
}
}];
$httpProvider.responseInterceptors.Push(interceptor);
angular-ui-router injecte le $http
service comme dépendance à $TemplateFactory
qui crée ensuite une référence circulaire à $http
dans le $httpProvider
lui-même lors de l'envoi de l'intercepteur.
La même exception de dépendance circulaire serait levée si vous essayez d’injecter le $http
service directement dans un intercepteur comme tel.
var interceptor = ['$location', '$q', '$http', function($location, $q, $http) {
Des exceptions de dépendance circulaires peuvent indiquer qu'il existe dans votre application une combinaison de problèmes pouvant entraîner des problèmes de stabilité. Si vous vous trouvez avec cette exception, vous devriez prendre le temps de regarder votre architecture pour éviter les dépendances qui finissent par se référencer.
Je suis d'accord avec la réponse ci-dessous que l'utilisation de la $injector
obtenir directement une référence au service souhaité n’est pas idéal et pourrait être considéré comme un anti-modèle.
L'émission d'un événement est une solution beaucoup plus élégante et découplée.
La question est un doublon de AngularJS: Injection de service dans un intercepteur HTTP (dépendance circulaire)
Je republie ma réponse à partir de ce fil ici:
Je pense que l’utilisation directe de $ injector est un anti-modèle.
Un moyen de rompre la dépendance circulaire consiste à utiliser un événement: au lieu d'injecter $ state, injectez $ rootScope. Au lieu de rediriger directement, faites
this.$rootScope.$emit("unauthorized");
plus
angular
.module('foo')
.run(function($rootScope, $state) {
$rootScope.$on('unauthorized', () => {
$state.transitionTo('login');
});
});
De cette façon, vous avez séparé les préoccupations:
La solution de Jonathan était géniale jusqu'à ce que j'essaye de sauver l'état actuel. Dans i-router v0.2.1 , l'état actuel ne semble pas être rempli lors du chargement initial de la page dans l'intercepteur.
Quoi qu'il en soit, je l'ai résolu en utilisant plutôt l'événement $ stateChangeError . L'événement $ stateChangeError vous donne à la fois à et de états, ainsi que l'erreur. C'est plutôt chouette.
$rootScope.$on('$stateChangeError',
function(event, toState, toParams, fromState, fromParams, error){
console.log('stateChangeError');
console.log(toState, toParams, fromState, fromParams, error);
if(error.status == 401){
console.log("401 detected. Redirecting...");
authService.deniedState = toState.name;
$state.go("login");
}
});