1.循环依赖问题。
那么,为什么会出现错误呢?以下是该过程的快速概述:
- 请求了 $http 服务。
- $httpProvider 被要求构建它。
- 在构建过程中,您注册了拦截器,该拦截器请求的 $http 服务尚不存在。
- 你得到“循环依赖”错误。
第一个解决方案。
使用 angular.injector() 创建你的依赖。请注意,您将创建另一个 $http 服务,独立于您的应用程序。
$httpProvider.interceptors.push(function($q) {
$injector = angular.injector();
return {
response: function(response) {
$injector.invoke(function($http) {
// This is the exterior $http service!
// This interceptor will not affect it.
});
}
};
});
第二种解决方案(更好)。
在您的拦截器中注入 $injector 并在 $http 初始化后使用它来检索依赖项,就在您需要它们的时候。这些依赖项是您的应用程序的注册服务,不会重新创建!
$httpProvider.interceptors.push(function($q, $injector) {
return {
response: function(response) {
$injector.invoke(function($http, someService) {
// $http is already constructed at the time and you may
// use it, just as any other service registered in your
// app module and modules on which app depends on.
});
}
};
});
2.拦截预防问题。
如果使用第二种方案,其实有两个问题:
- 如果你在拦截器中使用 $http 服务,你可能会遇到无限的拦截:你发送请求,拦截器捕获它,发送另一个,捕获另一个,再次发送,等等。
- 有时您只想防止请求被拦截。
$http 服务的 'config' 参数只是一个对象。您可以创建一个约定,提供自定义参数并在您的拦截器中识别它们。
例如,让我们在配置中添加“nointercept”属性并尝试复制每个用户请求。这是一个愚蠢的应用程序,但对理解行为很有用:
$httpProvider.interceptors.push(function($q, $injector) {
return {
response: function(response) {
if (response.config.nointercept) {
return $q.when(response); // let it pass
} else {
var defer = $q.defer();
$injector.invoke(function($http) {
// This modification prevents interception:
response.config.nointercept = true;
// Reuse modified config and send the same request again:
$http(response.config)
.then(function(resp) { defer.resolve(resp); },
function(resp) { defer.reject(resp); });
});
return defer.promise;
}
}
};
});
在拦截器中测试属性,您可以防止在控制器和服务中拦截:
app.controller('myController', function($http) {
// The second parameter is actually 'config', see API docs.
// This query will not be duplicated by the interceptor.
$http.get('/foo/bar', {nointercept: true})
.success(function(data) {
// ...
});
});