用于管理AngularJS中受限页面的拦截器

时间:2014-07-25 04:10:48

标签: javascript angularjs angular-http angular-promise angular-http-interceptors

我几天前刚刚开始使用AngularJS,我的拦截器出现问题,它拦截了服务器响应中的401状态。

它广播一个类型为" loginRequired"的消息。当返回401并在该事件上触发重定向时。

问题是如果我在没有登录的情况下尝试访问受限制的页面,我可以看到页面在我被重定向到登录页面之前闪烁了一会儿。我仍然是异步,承诺等的初学者。有人可以指出我做错了吗?

这是我的拦截器。正如你所看到的那样,它非常简单,但我把它缩小以解释我的观点,并且在进一步开发之前我试图理解它。

拦截器

var services = angular.module('services', []);

services.factory('myInterceptor', ['$q', '$rootScope',
  function($q,$rootScope) {

    var myInterceptor = {

      'responseError': function(rejection) {
        $rootScope.$broadcast('event:loginRequired');
        return $q.reject(rejection);
      }
    };

    return myInterceptor;
  }
]);

注入我的拦截器

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

限制页面的路线

.when('/restrictedPage', {
  templateUrl: 'partials/restrictedPage.html',
  controller: 'RestrictedPageController'
}).

受限制的页面控制器

controllers.controller('RestrictedPageController', function($scope) {

  //Some times the alert pops up, sometimes not.
  alert("Damn it I shouldn't be there");

});

$ rootScope事件监视器

$rootScope.$on('event:loginRequired', function() {

  //Only redirect if we aren't on free access page
  if ($location.path() == "/freeAccess")
    return;

  //else go to the login page
  $location.path('/home').replace();

});

我的问题显然与我处理拦截器和$ q的方式有关。我找到了另一种在github上创建拦截器的方法,但它不是官方文档使用的方式,所以我认为它可能是旧的方式而且不像放入它那样干净我认为是一家工厂。他只是在他的模块的配置函数中定义路由后放置此代码。但是这段代码有效,而且我没有让页面闪烁。

我在Github上找到的另一种方式

var interceptor = ['$rootScope', '$q', '$log',
  function(scope, $q, $log) {

    function success(response) {
      return response;
    }

    function error(response) {
      var status = response.status;

      if (status == 401) {
        var deferred = $q.defer();
        var req = {
          config: response.config,
          deferred: deferred
        };
        scope.$broadcast('event:loginRequired');
        return deferred.promise;
      }
      // otherwise
      return $q.reject(response);

    }

    return function(promise) {
      return promise.then(success, error);
    };

  }
];
$httpProvider.responseInterceptors.push(interceptor);

但我的目标不仅仅是让它运转起来。而且我讨厌咒语"如果它没有被打破,就不要修理它"。我想了解我的代码的问题是什么。谢谢!

1 个答案:

答案 0 :(得分:2)

不要从拦截器广播'event:loginRequired',而是尝试在拦截器中执行位置路径更改。广播会增加接收401和更改位置之间的延迟,并可能是屏幕“闪烁”的原因。

services.factory('myInterceptor', ['$q', '$rootScope', '$location',
  function($q, $rootScope, $location) {

    var myInterceptor = {

      'responseError': function(rejection) {
         if (response.status === 401 && $location.path() !== '/freeAccess') {
           //else go to the login page
           $location.path('/home').replace();
         }
         // otherwise
         return $q.reject(response);
      }
    };

    return myInterceptor;
  }
]);

您还可以在首次运行应用模块时执行HTTP请求,以便在用户获得授权后立即确定:

myApp.config(['$httpProvider', function($httpProvider) {
  $httpProvider.interceptors.push('myInterceptor');
}])
.run(function($http) {
  //if this returns 401, your interceptor will be triggered
  $http.get('some-endpoint-to-determine-auth'); 
});