拦截器

时间:2015-06-02 22:32:06

标签: angularjs angular-http-interceptors

我已经建立了一个使用API​​的AngularJS网站。此API提供的功能很少,如身份验证(Oauth)。

当API返回401错误时,表示access_token已过期,需要使用refresh_token进行刷新。

我在AngularJS中创建了一个拦截器。其目标是检查API返回的结果是否为401错误,如果是这种情况,则必须刷新令牌,然后处理先前被拒绝的请求。

问题是拦截器创建了一个无限循环。在初始请求第二次失败后,它应该停止,但它不会。

angular.module('myApp')
.factory('authInterceptor', function ($rootScope, $q, $window, $injector) {

  return {

    // If the API returns an error
    'responseError' : function(rejection) {

      // If it's a 401
      if (rejection.status == 401) {

        var deferred = $q.defer();

        $injector.get('$http').post('http://my-api.local/api/oauth/token', {
          grant_type    : 'refresh_token',
          client_id     : 'id',
          client_secret : 'secret',
          refresh_token : $window.sessionStorage.refresh_token
        }, {
          headers : {
            'Content-Type'  : 'application/x-www-form-urlencoded'
          },
          transformRequest  : function(obj) {
            var str = [];
            for(var p in obj)
            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
            return str.join("&");
          }
        })
        // New token request successfull
        .success(function(refreshResponse) {

          // Processing the failed request again (should fail again because I didn't saved the new tokens)
          $injector.get('$http')(rejection.config).success(function(data) {

            deferred.resolve(data);

          })
          .error(function(error, status) {

            deferred.reject();

          });

          return deferred.promise();

        })
        // New token request failure
        .error(function(error, status) {

          deferred.reject();
          // $location.path('users/login');

          return;

        });

      }
      // If it's another errorenter code here
      else
        return rejection;

    }

  }

});

所以这段代码:

  • 第一个请求失败时启动
  • 刷新令牌
  • 重试请求但又失败了(< - 我只是想让它停在这里)
  • 刷新令牌
  • 重试请求但又失败
  • 刷新令牌
  • 重试请求但又失败
  • 等...

1 个答案:

答案 0 :(得分:5)

我在我的应用中处理过这个问题。您的刷新请求需要包含skipIntercept: true之类的配置/标头变量。然后,当您将此作为失败的响应进行拦截时,您可以检查rejection.config.skipIntercept变量。如果确实如此,则直接转到$q.reject(rejection)

你在哪里:

if (rejection.status == 401) {

将其更改为:

if (rejection.status == 401 && !rejection.config.skipIntercept) {

然后在上面:

     headers : {
        'Content-Type'  : 'application/x-www-form-urlencoded'
     },

您需要添加:

     skipIntercept: true,

     headers: {
        'Content-Type'  : 'application/x-www-form-urlencoded'
     },

PS。 there's an existing solution你可以使用。