简体   繁体   English

角度拦截器如何工作?

[英]How angular interceptors works?

I was learning angular interceptors today. 我今天正在学习角度拦截器。 I did some samples to to better understand the concept. 我做了一些示例以更好地理解这个概念。 Here is small sample. 这是小样本。

 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> 

When I am doing console.log(config) inside request function, here is the output on the console. 当我在请求函数中执行console.log(config) ,这是控制台上的输出。 在此处输入图片说明

I am not getting how responseTimestamp appear in the config object of request where as its defined inside response function 我没有得到responseTimestamp如何出现在请求的配置对象中,如其在响应函数中定义的

Note I used the source code for 1.2.x which is the one added in the question. 注意我使用了源代码1.2.x,这是在问题中添加的源代码。

$httpProvider is a provider that gives you $http service. $httpProvider是为您提供$http服务的提供程序。

As a provider, in config time exposes a public array - there you just add all strings from services names you wanted to be injected in your response/requests. 作为提供者,在配置时公开一个公共数组-您只需在其中添加要注入响应/请求中的服务名称中的所有字符串。

That is what you do here 那就是你在这里做的

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

and it can be only done in config time because per docs providers can be configured before the application starts 并且只能在配置时间内完成,因为可以在应用程序启动之前配置每个文档提供程序

You can see the exposed array in the source code in line 159 您可以在第159行的源代码中看到公开的数组

var responseInterceptorFactories = this.responseInterceptors = [];

When you request the $http service, injecting it into your service/controller, $get function is executed. 当您请求$http服务并将其注入服务/控制器时,将执行$get函数。 In that function, your array of interceptors is iterated, as you can see in source code in line 179 在该函数中,将对拦截器数组进行迭代,如您在第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));
        }
      });
    });

Per convention, they reverse the order. 按照惯例,它们会颠倒顺序。 You can see that using the string, they get a reference to the function using $injector.get or $injector.invoke , and using $q.when() we can introduce them to the promises chain, even if they are synchronous code - See this Can I use $q.all in AngularJS with a function that does not return a .promise? 您可以看到,使用字符串,它们可以使用$injector.get$injector.invoke来引用函数,并且可以使用$q.when()将它们引入promise链,即使它们是同步代码, 可以在AngularJS中将$ q.all与不返回.promise的函数一起使用吗? if you are not sure what I meant about $q.when() 如果您不确定$q.when()含义,

So far we have an array with functions, which are all promise-like (thanks to $q.when() ). 到目前为止,我们有了一个带有函数的数组,这些函数都像promise一样(感谢$q.when() )。 When you request data through $http like this 当您通过$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")
  });

even though you have the .get() , is just a shortcut for all the same functionality which is here 即使您拥有.get() ,也只是这里所有相同功能的快捷方式

In the code the relevant part is this one: 代码中的相关部分是这一部分:

First, a chain array is created with two values: an inner function which is not important for our purpose (but it returns a promise - this is important), and undefined value. 首先,创建一个具有两个值的链数组:一个内部函数对我们的目的并不重要(但它返回一个promise-这很重要),以及一个未定义的值。

Our array with interceptors is iterated, and request interceptors are added at the beginning (before the request) and response at the end. 我们的带有拦截器的数组被迭代,请求拦截器在开始时(在请求之前)添加,在响应结束时添加。 Like this 像这样

   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, having the chain complete (remember our array of interceptors was full of promises), the code iterates it, adding all of them using .then() , causing all of them to be executed in a chain, following promises chaining (you can google that) 然后,使链完整(记住我们的拦截器数组中充满了诺言),代码对其进行迭代,并使用.then()将它们全部添加,使所有它们在诺言链接之后在链中执行(您可以谷歌那个)

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

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

Finally, the callback you add in success and error is added at the very end of the chain and the promise is returned 最后, success添加和error添加的回调将添加到链的最后,并返回promise

 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;

The only part I am not sure about is the use of undefined in the chain array 我不确定的唯一部分是在链数组中使用undefined

Summary 摘要

You add the name for your services, $HttpProvider uses $invoke service to get them and adds them in the promise chain using $q.when() , returning a promise. 您为服务添加名称, $HttpProvider使用$invoke服务获取它们,并使用$q.when()将它们添加到$q.when()链中,返回一个$q.when() At the end of that, your callbacks for a specific $http request is added. 最后,添加了针对特定$http请求的回调。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM