Ich versuche, einen HTTP-Interceptor für meine AngularJS-App zu schreiben, um die Authentifizierung zu handhaben.
Dieser Code funktioniert, aber ich mache mir Sorgen um das manuelle Einfügen eines Dienstes, da ich dachte, Angular sollte dies automatisch erledigen:
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;
}
};
})
}]);
Was ich anfing zu tun, aber auf zirkuläre Abhängigkeitsprobleme stieß:
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');
});
Ein weiterer Grund, warum ich besorgt bin, ist, dass der Abschnitt über $ http in den Angular Docs einen Weg zu zeigen scheint, wie Abhängigkeiten auf "normale Weise" in einen HTTP-Interceptor injiziert werden können. Siehe ihren Code-Ausschnitt unter "Interceptors":
// 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');
Wohin soll der obige Code gehen?
Ich denke, meine Frage ist, wie man das richtig macht.
Danke, und ich hoffe, meine Frage war klar genug.
javascript
angularjs
shaunlim
quelle
quelle
$http
. Der einzige Weg, den ich gefunden habe, ist die Verwendung$injector.get
, aber es wäre toll zu wissen, ob es eine gute Möglichkeit gibt, den Code zu strukturieren, um dies zu vermeiden.Antworten:
Sie haben eine zirkuläre Abhängigkeit zwischen $ http und Ihrem AuthService.
Mit dem
$injector
Dienst lösen Sie das Henne-Ei-Problem, indem Sie die Abhängigkeit von $ http vom AuthService verzögern.Ich glaube, dass das, was Sie getan haben, der einfachste Weg ist, es zu tun.
Sie können dies auch tun, indem Sie:
run()
Block anstelle einesconfig()
Blocks zu tun, reicht möglicherweise bereits aus). Aber können Sie garantieren, dass $ http noch nicht aufgerufen wurde?AuthService.setHttp()
oder ähnliches registrieren .quelle
run()
Block registrieren , da Sie $ httpProvider nicht in einen Ausführungsblock einfügen können. Dies können Sie nur in der Konfigurationsphase tun.Das habe ich letztendlich getan
Hinweis: Die
$injector.get
Aufrufe sollten innerhalb der Methoden des Interceptors liegen. Wenn Sie versuchen, sie an anderer Stelle zu verwenden, wird in JS weiterhin ein zirkulärer Abhängigkeitsfehler angezeigt.quelle
Ich denke, die direkte Verwendung des $ -Injektors ist ein Antimuster.
Eine Möglichkeit, die zirkuläre Abhängigkeit zu überwinden, besteht darin, ein Ereignis zu verwenden: Anstatt $ state zu injizieren, injizieren Sie $ rootScope. Anstatt direkt umzuleiten, tun Sie dies
Plus
quelle
Eine schlechte Logik führte zu solchen Ergebnissen
Tatsächlich gibt es keinen Grund zu suchen, ob der Benutzer in Http Interceptor verfasst ist oder nicht. Ich würde empfehlen, alle HTTP-Anforderungen in einen einzelnen .service (oder .factory oder in .provider) zu verpacken und für ALLE Anforderungen zu verwenden. Bei jedem Aufruf der Funktion können Sie überprüfen, ob der Benutzer angemeldet ist oder nicht. Wenn alles in Ordnung ist, erlauben Sie die Sendeanforderung.
In Ihrem Fall sendet die Angular-Anwendung in jedem Fall eine Anfrage, Sie überprüfen nur die Autorisierung dort und danach sendet JavaScript eine Anfrage.
Kern Ihres Problems
myHttpInterceptor
wird unter$httpProvider
Instanz aufgerufen . IhreAuthService
Verwendungen$http
oder$resource
, und hier haben Sie eine Abhängigkeitsrekursion oder eine zirkuläre Abhängigkeit. Wenn Sie diese Abhängigkeit entfernen,AuthService
wird dieser Fehler nicht angezeigt.Auch wie @Pieter Herroelen betonte, könnten Sie diesen Interceptor in Ihr Modul einfügen
module.run
, aber dies ist eher ein Hack, keine Lösung.Wenn Sie sauberen und selbstbeschreibenden Code erstellen möchten, müssen Sie einige der SOLID-Prinzipien einhalten.
Zumindest das Prinzip der Einzelverantwortung wird Ihnen in solchen Situationen sehr helfen.
quelle
Wenn Sie nur nach dem Auth-Status suchen (isAuthorized ()), würde ich empfehlen, diesen Status in ein separates Modul zu setzen, z. B. "Auth", das nur den Status enthält und $ http selbst nicht verwendet.
Auth-Modul:
(Ich habe localStorage verwendet, um die Sitzungs-ID hier auf der Clientseite zu speichern. Sie können dies jedoch auch nach einem Aufruf von $ http in Ihrem AuthService festlegen.)
quelle