2017-06-25 67 views
0

我正在开发一个Angular webapp,它使用API​​来获取一些数据。 要获得这些数据,我必须发送一个智威汤逊。 我创建,为了调用一个PHP文件,以获得令牌服务:如何在AngularJS中刷新过期的jwt令牌

(function() { 
'use strict'; 

angular 
.module('MyApp') 
.factory('TokenService', Service); 

function Service($http, $localStorage) { 

    var service = {}; 

    service.getToken = getToken; 

    return service; 

    function getToken() { 
     return $http.post('gettoken.php'); 
    } 
}})(); 

而我做的是在.RUN块我把它和存储接收的令牌:

function run($rootScope, $http, $location, $localStorage, TokenService) { 
    TokenService.getToken().then(function(response) { 
     $localStorage.token = response.data.token; 
    }); 
    console.log('token: ' + $localStorage.token); 
    $http.defaults.headers.common.Authorization = 'Bearer ' + $localStorage.token; 
}})(); 

每过几分钟,令牌就会过期,因此我必须请求另一个令牌,以便用户可以继续与API进行交互。

为了解决这个问题,我的第一个方法是使用.config块拦截401错误(令牌过期)并要求另一个令牌,但这是不可能的,因为据我所知,不可能注入服务的.config块:

function config2($httpProvider) { 
    $httpProvider.interceptors.push(function ($q, $rootScope) { 
     return { 
      'response': function (response) { 
      //Will only be called for HTTP up to 300 
      console.log(response); 
      return response; 
     }, 
     'responseError': function (rejection) { 
      if(rejection.status === 401) { 
       var deferred = $q.defer(); 
       TokenService.getToken(function() { 
        retryHttpRequest(response.config, deferred); 
       }); 
       return deferred.promise; 
      } else { 
       return response; 
      } 
      function retryHttpRequest(config, deferred){ 
       function successCallback(response){ 
       deferred.resolve(response); 
       } 
       function errorCallback(response){ 
       deferred.reject(response); 
       } 
       var $http = $injector.get('$http'); 
       $http(config).then(successCallback, errorCallback); 
      } 
     } 
    }; 
}); 
} 

事实上,当我执行的web应用程序,它说,TokenService没有定义,如果我注入TokenService,显然它创建了一个圆圈扶养:

angular.js:66 Uncaught Error: [$injector:cdep] Circular dependency found: $http <- TokenService <- $http <- $templateRequest <- $route 
http://errors.angularjs.org/1.6.4/$injector/cdep?p0=%24http%20%3C-%20TokenService%20%3C-%20%24http%20%3C-%20%24templateRequest%20%3C-%20%24route 
    at angular.js:66 
    at getService (angular.js:4936) 
    at injectionArgs (angular.js:4969) 
    at Object.invoke (angular.js:4995) 
    at Object.enforcedReturnValue [as $get] (angular.js:4836) 
    at Object.invoke (angular.js:5003) 
    at angular.js:4795 
    at getService (angular.js:4944) 
    at injectionArgs (angular.js:4969) 
    at Object.invoke (angular.js:4995) 

这是一个非常愚蠢的情况,但我花了整整一天试图fi寻找最佳解决方案。 一旦拦截器检测到401 responseError,我试图简单地重新加载页面,但这不是最佳的,因为用户看到网络刷新,并且他丢失了为请求插入的所有数据。

如果有的话,你不得不处理这类问题,可以为了解决它共享任何方式这将是巨大的。

回答

1

这可能是因为$http服务取决于您的拦截器,您的TokenService取决于$http服务,而您的拦截器取决于TokenService。这会导致循环依赖。

看来你已经在使用$injector来即时注入$ http-service,所以要解决你的循环依赖问题,用同样的方法注入你的TokenService可能会解决你的问题。

var TokenService = $injector.get('TokenService'); 

我之前在同样的问题,迷迷糊糊的,所以如果它的任何帮助,您可以check my solution on GitHub

+0

非常感谢您的帮助。 我应用了你说的。现在的问题是当我在ResponseError中调用getToken时:它返回新的令牌,但它不适用于当前的401请求,所以我收到新的令牌,但对API的请求仍然失败。 我正在阅读你的解决方案在GitHub上,我希望我可以用该代码解决它。 非常感谢! – Hmorv

+1

我终于用你的工厂作为例子调整了我的代码。它的作品相当不错!谢谢! – Hmorv