2016-08-20 115 views
2

我今天正在学习角度拦截器。我做了一些样本来更好地理解这个概念。这里是小样本。角度拦截器如何工作?

var app = angular.module("myApp", []); 
 

 
app.factory("timestampMaker", [ 
 
    function() { 
 
    var timestampMaker = { 
 
     request: function(config) { 
 
     console.log(config); 
 
     config.requestTimestamp = new Date().getTime(); 
 
     return config; 
 
     }, 
 
     response: function(response) { 
 

 
     response.config.responseTimestamp = new Date().getTime(); 
 
     return response; 
 
     } 
 
    }; 
 
    return timestampMaker; 
 
    } 
 
]); 
 

 
app.config(['$httpProvider', 
 
    function($httpProvider) { 
 
    $httpProvider.interceptors.push('timestampMaker'); 
 
    } 
 
]); 
 

 
app.run(function($http) { 
 
    $http.get('https://api.github.com/users/naorye/repos').then(function(response) { 
 
    console.log(response); 
 
    var time = response.config.responseTimestamp - response.config.requestTimestamp; 
 
    console.log("The request took" + (time/1000) + "seconds") 
 
    }); 
 
});
<html ng-app="myApp"> 
 

 
<head> 
 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
</head> 
 

 
</html>

当我做console.log(config)请求函数里面,这里是控制台上的输出。 enter image description here

我没有得到如何responseTimestamp出现在请求中的配置对象,其中作为其响应函数中定义

回答

0

我使用的源代码的1.2.x这是一个在的问题添加。

$httpProvider是一个为您提供$http服务的提供商。

作为一个提供者,在配置时暴露一个公共数组 - 你只需添加你想要注入到你的响应/请求中的所有服务名字的字符串。

这就是你在这里做

app.config(['$httpProvider', 
    function($httpProvider) { 
    $httpProvider.interceptors.push('timestampMaker'); 
    } 
]); 

,它可以在配置时间只能做,因为每docs提供商可以在应用程序之前配置的内容开始

你可以看到在暴露阵列source code在行159

var responseInterceptorFactories = this.responseInterceptors = []; 

当你请求$http服务,它注射到你的服务/控制器, $get函数被执行。在该功能,您的拦截器阵列迭代,因为你可以在source code排队见179

var reversedInterceptors = []; 
    forEach(responseInterceptorFactories, function(interceptorFactory, index) { 
     var responseFn = isString(interceptorFactory) ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory); 

     /** 
     * Response interceptors go before "around" interceptors (no real reason, just 
     * had to pick one.) But they are already reversed, so we can't use unshift, hence 
     * the splice. 
     */ 
     reversedInterceptors.splice(index, 0, { 
     response: function(response) { 
      return responseFn($q.when(response)); 
     }, 
     responseError: function(response) { 
      return responseFn($q.reject(response)); 
     } 
     }); 
    }); 

按照惯例,他们颠倒顺序。您可以看到,使用字符串,他们使用$injector.get$injector.invoke获得对该函数的引用,并且使用$q.when()我们可以将它们引入承诺链,即使它们是同步代码 - 如果您不确定我的意思,请参阅此Can I use $q.all in AngularJS with a function that does not return a .promise?$q.when()

到目前为止,我们有一个函数的数组,这些都是诺言般的(感谢$q.when())。当你请求的数据thorught $http这样

$http.get('https://api.github.com/users/naorye/repos').then(function(response) { 
    console.log(response); 
    var time = response.config.responseTimestamp - response.config.requestTimestamp; 
    console.log("The request took" + (time/1000) + "seconds") 
    }); 

即使你有.get(),只是对所有相同功能的shorcut这是here

在代码中的相关部分是这样的一个:

首先用两个值创建一个链式数组:一个内部函数对我们来说不是重要的(但它返回一个承诺 - 这很重要)和未定义的值。

我们使用拦截器的数组是迭代的,请求拦截器在开始时(请求之前)和响应结束处添加。像这样

function serverRequest { 
     // some code 
    }; 
    var chain = [serverRequest, undefined]; 
    var promise = $q.when(config); 

    // apply interceptors 
    forEach(reversedInterceptors, function(interceptor) { 
     if (interceptor.request || interceptor.requestError) { 
     chain.unshift(interceptor.request, interceptor.requestError); 
     } 
     if (interceptor.response || interceptor.responseError) { 
     chain.push(interceptor.response, interceptor.responseError); 
     } 
    }); 

然后,具有链条完整的(记住我们的拦截器的阵列是充满希望的),代码迭代时,使用.then()将所有这些,使所有的人都在链执行,以下承诺链接(你可以谷歌认为)

while(chain.length) { 
     var thenFn = chain.shift(); 
     var rejectFn = chain.shift(); 

     promise = promise.then(thenFn, rejectFn); 
    } 

最后,回调你success添加和error在链的最末端,并将该承诺返回

promise.success = function(fn) { 
    promise.then(function(response) { 
    fn(response.data, response.status, response.headers, config); 
    }); 
    return promise; 
}; 

promise.error = function(fn) { 
    promise.then(null, function(response) { 
    fn(response.data, response.status, response.headers, config); 
    }); 
    return promise; 
}; 

return promise; 

我不知道的只有部分是链阵列中使用的undefined

摘要

您为您的服务添加姓名,$HttpProvider使用$invoke服务,让他们,并增加了他们承诺链使用$q.when(),返回承诺。在那结束时,您添加了对特定$http请求的回拨