J'essaie d'écrire un intercepteur HTTP pour mon application AngularJS pour gérer l'authentification.
Ce code fonctionne, mais je suis préoccupé par l'injection manuelle d'un service car je pensais qu'Angular est censé gérer cela automatiquement:
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(function ($location, $injector) {
return {
'request': function (config) {
//injected manually to get around circular dependency problem.
var AuthService = $injector.get('AuthService');
console.log(AuthService);
console.log('in request interceptor');
if (!AuthService.isAuthenticated() && $location.path != '/login') {
console.log('user is not logged in.');
$location.path('/login');
}
return config;
}
};
})
}]);
Ce que j'ai commencé à faire, mais j'ai rencontré des problèmes de dépendance circulaire:
app.config(function ($provide, $httpProvider) {
$provide.factory('HttpInterceptor', function ($q, $location, AuthService) {
return {
'request': function (config) {
console.log('in request interceptor.');
if (!AuthService.isAuthenticated() && $location.path != '/login') {
console.log('user is not logged in.');
$location.path('/login');
}
return config;
}
};
});
$httpProvider.interceptors.push('HttpInterceptor');
});
Une autre raison pour laquelle je suis préoccupé est que la section sur $ http dans Angular Docs semble montrer un moyen d'obtenir des dépendances injectées de la «manière régulière» dans un intercepteur Http. Voir leur extrait de code sous "Intercepteurs":
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return {
// optional method
'request': function(config) {
// do something on success
return config || $q.when(config);
},
// optional method
'requestError': function(rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
},
// optional method
'response': function(response) {
// do something on success
return response || $q.when(response);
},
// optional method
'responseError': function(rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
};
}
});
$httpProvider.interceptors.push('myHttpInterceptor');
Où doit aller le code ci-dessus?
Je suppose que ma question est de savoir quelle est la bonne façon de procéder?
Merci et j'espère que ma question était assez claire.
la source
$http
. Le seul moyen que j'ai trouvé est de l'utiliser$injector.get
, mais ce serait bien de savoir s'il existe un bon moyen de structurer le code pour éviter cela.Réponses:
Vous avez une dépendance circulaire entre $ http et votre AuthService.
Ce que vous faites en utilisant le
$injector
service, c'est résoudre le problème de la poule et de l'œuf en retardant la dépendance de $ http sur AuthService.Je crois que ce que vous avez fait est en fait la manière la plus simple de le faire.
Vous pouvez également le faire en:
run()
bloc au lieu d'unconfig()
bloc pourrait déjà faire l'affaire). Mais pouvez-vous garantir que $ http n'a pas déjà été appelé?AuthService.setHttp()
ou quelque chose.la source
run()
bloc, car vous ne pouvez pas injecter $ httpProvider dans un bloc d'exécution. Vous ne pouvez le faire que dans la phase de configuration.C'est ce que j'ai fini par faire
Remarque: les
$injector.get
appels doivent être dans les méthodes de l'intercepteur, si vous essayez de les utiliser ailleurs, vous continuerez à obtenir une erreur de dépendance circulaire dans JS.la source
Je pense que l'utilisation directe de $ injector est un anti-modèle.
Un moyen de rompre la dépendance circulaire est d'utiliser un événement: au lieu d'injecter $ state, injectez $ rootScope. Au lieu de rediriger directement, faites
plus
la source
La mauvaise logique a fait de tels résultats
En fait, il est inutile de rechercher si l'utilisateur a été créé ou non dans Http Interceptor. Je recommanderais d'envelopper toutes vos demandes HTTP dans un seul .service (ou .factory, ou dans .provider), et de l'utiliser pour TOUTES les demandes. À chaque fois que vous appelez la fonction, vous pouvez vérifier si l'utilisateur est connecté ou non. Si tout va bien, autorisez l'envoi de la demande.
Dans votre cas, l'application Angular enverra une demande dans tous les cas, il vous suffit de vérifier l'autorisation là-bas, et après cela, JavaScript enverra la demande.
Au cœur de votre problème
myHttpInterceptor
est appelé sous$httpProvider
instance. VosAuthService
utilisations$http
, ou$resource
, et ici vous avez une récursivité de dépendance ou une dépendance circulaire. Si vous supprimez cette dépendance deAuthService
, vous ne verrez pas cette erreur.De plus, comme @Pieter Herroelen l'a souligné, vous pouvez placer cet intercepteur dans votre module
module.run
, mais ce sera plus comme un hack, pas une solution.Si vous êtes prêt à faire du code propre et auto-descriptif, vous devez suivre certains des principes SOLID.
Au moins le principe de responsabilité unique vous aidera beaucoup dans de telles situations.
la source
Si vous ne faites que vérifier l'état d'authentification (isAuthorized ()), je recommanderais de mettre cet état dans un module séparé, dites "Auth", qui contient simplement l'état et n'utilise pas $ http lui-même.
Module d'authentification:
(J'ai utilisé localStorage pour stocker le sessionId côté client ici, mais vous pouvez également le définir dans votre AuthService après un appel $ http par exemple)
la source