Estoy tratando de escribir un interceptor HTTP para que mi aplicación AngularJS maneje la autenticación.
Este código funciona, pero me preocupa inyectar manualmente un servicio ya que pensé que se supone que Angular maneja esto automáticamente:
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;
}
};
})
}]);
Lo que comencé a hacer, pero encontré problemas de dependencia circular:
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');
});
Otra razón por la que me preocupa es que la sección sobre $ http en Angular Docs parece mostrar una forma de inyectar las dependencias de la "forma normal" en un interceptor Http. Consulte su fragmento de código en "Interceptores":
// 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');
¿Dónde debería ir el código anterior?
Supongo que mi pregunta es ¿cuál es la forma correcta de hacer esto?
Gracias, y espero que mi pregunta haya sido lo suficientemente clara.
javascript
angularjs
Shaunlim
fuente
fuente
$http
. La única forma de evitarlo que he encontrado es usar$injector.get
, pero sería genial saber si hay una buena manera de estructurar el código para evitar esto.Respuestas:
Tiene una dependencia circular entre $ http y su AuthService.
Lo que está haciendo al usar el
$injector
servicio es resolver el problema del huevo y la gallina al retrasar la dependencia de $ http en AuthService.Creo que lo que hiciste es en realidad la forma más sencilla de hacerlo.
También puede hacer esto:
run()
bloque en lugar de unconfig()
bloque podría ser suficiente). ¿Pero puede garantizar que no se haya llamado a $ http ya?AuthService.setHttp()
o algo.fuente
run()
bloque, porque no puede inyectar $ httpProvider en un bloque de ejecución. Solo puede hacer eso en la fase de configuración.Esto es lo que terminé haciendo
Nota: Las
$injector.get
llamadas deben estar dentro de los métodos del interceptor, si intenta usarlas en otro lugar, continuará obteniendo un error de dependencia circular en JS.fuente
Creo que usar el inyector $ directamente es un antipatrón.
Una forma de romper la dependencia circular es usar un evento: en lugar de inyectar $ state, inyecte $ rootScope. En lugar de redirigir directamente, haz
más
fuente
La mala lógica hizo tales resultados
En realidad, no tiene sentido buscar si el usuario es autor o no en Http Interceptor. Recomendaría envolver todas sus solicitudes HTTP en un solo .service (o .factory, o en .provider), y usarlo para TODAS las solicitudes. Cada vez que llame a la función, puede verificar si el usuario inició sesión o no. Si todo está bien, permita enviar solicitud.
En su caso, la aplicación Angular enviará la solicitud en cualquier caso, solo verifica la autorización allí, y luego JavaScript enviará la solicitud.
Núcleo de tu problema
myHttpInterceptor
se llama bajo$httpProvider
instancia. TusAuthService
usos$http
, o$resource
, y aquí tienes la recursividad de dependencia, o dependencia circular. Si elimina esa dependencia deAuthService
, no verá ese error.Además, como señaló @Pieter Herroelen, podría colocar este interceptor en su módulo
module.run
, pero esto será más como un truco, no una solución.Si está preparado para hacer un código limpio y autodescriptivo, debe seguir algunos de los principios SÓLIDOS.
Al menos el principio de Responsabilidad Única le ayudará mucho en tales situaciones.
fuente
Si solo está comprobando el estado de autenticación (isAuthorized ()), recomendaría poner ese estado en un módulo separado, diga "Auth", que solo contiene el estado y no usa $ http en sí.
Módulo de autenticación:
(Usé localStorage para almacenar el sessionId en el lado del cliente aquí, pero también puede configurar esto dentro de su AuthService después de una llamada $ http, por ejemplo)
fuente