AngularJS中Interceptor出现Circular Dependency错误及后续问题求助
First Circular Dependency Cause
Let's break down your initial error chain:
Circular dependency found: $http <- Global <- authInterceptor <- $http <- $templateRequest <- $compile
Here's why this happens:
- You registered
authInterceptorwith$httpProvider.interceptors, which means $http depends on authInterceptor to process requests and responses. - Your
authInterceptordirectly injects theGlobalfactory. - The
Globalfactory itself injects$http. - This creates a closed loop: $http requires authInterceptor, which requires Global, which requires $http. AngularJS's injector can't resolve this circular reference during initialization, hence the error.
Why the Error Persisted After Removing $http from Global?
After you removed $http from Global, you hit a new circular chain:
$templateRequest <- $$animateQueue <- $animate <- $$interimElement <- $mdDialog <- Global <- authInterceptor <- $http <- $templateRequest <- $compile
The issue here is that $mdDialog (which you inject into Global) has a deep dependency chain that eventually leads back to $templateRequest—and $templateRequest relies on $http to load templates. Since $http still depends on your authInterceptor, and authInterceptor depends on Global (which depends on $mdDialog), you're still stuck in a circular loop. Even if you never call $templateRequest directly, AngularJS resolves all dependencies during service initialization, so the chain gets triggered automatically.
Solutions to Fix the Circular Dependency
1. Use $injector for Lazy Injection
Instead of injecting Global directly into authInterceptor, inject $injector and retrieve Global only when you need it (inside the responseError handler). This delays the resolution of Global until runtime, breaking the initialization-time circular chain:
app.factory("authInterceptor", authInterceptor); authInterceptor.$inject = ["$q","$injector"]; function authInterceptor($q, $injector) { return { 'responseError': function (response) { if (response.status === 401 || response.status === 403) { // Lazy-load Global to avoid circular dependency during initialization const Global = $injector.get('Global'); Global.show_fail("Connection expired, please authenticate again"); } return $q.reject(response); } }; }
2. Split Global Factory's Responsibilities
A cleaner long-term fix is to separate the error notification logic from the HTTP-related logic in your Global factory. Create a dedicated service for displaying notifications, which doesn't depend on $http or any services that link back to $http:
// New dedicated notification service app.factory('NotificationService', ['$mdDialog','$timeout', function($mdDialog, $timeout){ return { show_fail: function(message) { // Copy your existing show_fail implementation here } }; }]);
Then update your authInterceptor to depend on NotificationService instead of Global:
app.factory("authInterceptor", authInterceptor); authInterceptor.$inject = ["$q","NotificationService"]; function authInterceptor($q, NotificationService) { return { 'responseError': function (response) { if (response.status === 401 || response.status === 403) { NotificationService.show_fail("Connection expired, please authenticate again"); } return $q.reject(response); } }; }
You can also have your original Global factory inject NotificationService if it needs to display errors too. This way, you eliminate the circular chain entirely by breaking the direct link between the interceptor and the service that depends on HTTP-related components.
内容的提问来源于stack exchange,提问作者TotoNaBendo

