2014-09-04 64 views
0

我們正在使用AngularJS和Ionic框架創建基於PhoneGap的應用程序。AngularJS回調流程

這個應用程序是一個商店管理系統,它使用OAuth2與現有的網絡應用程序綁定。

該應用程序包含一個'訂單'視圖,顯示客戶收到的訂單列表。在加載訂單列表之前,以下函數將驗證用戶的訪問令牌是否仍然有效,如果沒有,則獲取新令牌。

function verifyAccessToken() { 


      var now = new Date().getTime(); 

      if (now > tokenStore.access_token_expiry_date) { 

       // renew access token 
       $http({ 
        url: '*API URL*/token', 
        method: "POST", 
        data: { 
         refresh_token : tokenStore.refresh_token, 
         grant_type : 'refresh_token', 
         client_id: clientId, 
         client_secret: clientSecret, 
         redirect_uri: redirectURI 
        }, 
        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("&"); 
        }      
       }) 
       .success(function (data, status, headers, config) { 
        tokenStore['access_token'] = data.access_token; 
        var expiresAt = now + parseInt(data.expires_in, 10) * 1000 - 10000; 
        tokenStore['access_token_expiry_date'] = expiresAt; 
        console.log(data.access_token); 
       }) 
       .error(function (data, status, headers, config) { 
        if(status=='404') { 
         $rootScope.$emit('serviceUnavailable'); 
        } 
        if(status=='400' || status=='401') { 
         $rootScope.$emit('tokenUnauthorized'); 
        } 
        console.log(status); 
        console.log(data);   
       }); 
      } 


     }; 

然後調用使用新的訪問令牌

return $http({method: 'GET', url: '*API URL*?access_token=' + tokenStore.access_token, params: {}}) 
       .error(function(data, status, headers, config) { 
        if(status=='404') { 
         $rootScope.$emit('serviceUnavailable'); 
        } 
        if(status=='401') { 
         $rootScope.$emit('tokenUnauthorized'); 
        } 
        console.log(status); 
        console.log(data); 
       });  
     } 

問題的命令列表是在HTTP GET不等待VerifyAccessToken功能來完成。

這是如何構建的,以避免這個問題?

任何意見,你可以提供將不勝感激。

更新2(後klyd的答案):

我在更新了兩個功能OAuth的angular.js描述如下:

verifyAccessToken函數現在如下:

function verifyAccessToken() { 
     var deferred = $q.defer(); 

     if ((new Date().getTime()) < tokenStore.access_token_expiry_date) { 
      /* token is still valid, resolve the deferred and bail early */ 
      deferred.resolve(); 
      return deferred.promise; 
     } 

     /* token is not valid, renew it */ 
     alert('getting new access token') 
     $http({ 
      url: 'https://' + tokenStore.site_name + '.somedomain.com/api/oauth2/token', 
      method: "POST", 
      data: { 
       refresh_token : tokenStore.refresh_token, 
       grant_type : 'refresh_token', 
       client_id: clientId, 
       client_secret: clientSecret, 
       redirect_uri: redirectURI 
      }, 
      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("&"); 
      }      
     }).success(function (data, status, headers, config) { 
      tokenStore['access_token'] = data.access_token; 
      var now = new Date().getTime(); 
      var expiresAt = now + parseInt(data.expires_in, 10) * 1000 - 10000; 
      tokenStore['access_token_expiry_date'] = expiresAt; 
      console.log(data.access_token); 
      deferred.resolve(); 
     }) 
     .error(function (data, status, headers, config) { 
      if(status=='404') { 
       $rootScope.$emit('serviceUnavailable'); 
      } 
      if(status=='400' || status=='401') { 
       $rootScope.$emit('tokenUnauthorized'); 
      } 
      console.log(status); 
      console.log(data); 
      deferred.reject(); // as the last step, reject the deferred, there was a failure 
     }); 

     return deferred.promise; 
    } 

和getOrders函數現在讀取如下:

執行功能getOrders時
function getOrders() { 

     verifyAccessToken().then(
      function() { 
       return $http({method: 'GET', url: 'https://' + tokenStore.site_name + '.somedomain.com/api/1.0/orders?access_token=' + tokenStore.access_token, params: {}}) 
        .error(function(data, status, headers, config) { 
         if(status=='404') { 
          $rootScope.$emit('serviceUnavailable'); 
         } 
         if(status=='401') { 
          $rootScope.$emit('tokenUnauthorized'); 
         } 
         console.log(status); 
         console.log(data); 
        }); 
      }, 
      function() { 
       /* code to handle a failure of renewing the token */ 
      }); 

    } 

controllers.js文件現在引發以下錯誤。

類型錯誤:無法讀取此之前,沒有任何問題工作的不確定

.controller('OrdersCtrl', function ($scope, $stateParams, oauth, $ionicLoading) { 

     function loadOrders() { 

     $scope.show(); 

     oauth.getOrders() 
      .success(function (result) { 
       $scope.hide(); 
       $scope.orders = result; 
       console.log(result); 
       // Used with pull-to-refresh 
       $scope.$broadcast('scroll.refreshComplete'); 
      }) 
      .error(function(data) { 
       $scope.hide(); 
      }); 
    } 
}) 

財產 '成功'。有什麼想法嗎?

+0

你還沒有完全發佈足夠的代碼呢。例如,「verifyAccessToken」在哪裏實際調用?它在哪裏定義 - 它有$ http/$ rootScope,但沒有直接注入,是在關閉?你能把一個簡化的jsFiddle或plunkr放在一起來說明這個機制嗎?你也應該再次查看我的例子,你聲明瞭延遲變量,但不對它做任何事情。 – klyd 2014-09-04 11:40:51

+0

對不起 - 漫長的一天。我已經更新了上面的代碼,希望現在更有意義 – 2014-09-04 20:52:19

+0

你快到了。看看你的'getOrders'函數,它不會立即返回任何東西,這就是爲什麼沒有'成功'方法。你需要返回'getOrders'中的'verifyAccessToken()'行。之後,你需要從'.success'和'.error'改變爲'.then'的調用(錯誤和成功是'HttpPromise'的特殊功能)。 – klyd 2014-09-04 21:27:33

回答

0

返回值$httppromise。每當一個函數返回一個promise時,它最有可能關於執行異步操作。這意味着函數調用會立即返回一個對象,然後您可以在該操作完成時用它來調用其他方法。

在這種情況下,您應該重新安排您的verifyAccessToken函數以返回它自己的承諾。

喜歡的東西:

function verifyAccessToken() { 
    var deferred = $q.defer(); 

    if ((new Date().getTime()) < tokenStore.access_token_expiry_date) { 
     /* token is still valid, resolve the deferred and bail early */ 
     deferred.resolve(); 
     return deferred.promise; 
    } 

    /* token is not valid, renew it */ 
    $http({ 
     /* stuff */ 
    }).success(function() { 
     /* stuff */ 
     deferred.resolve(); // resolve the deferred as the last step 
    }) 
    .error(function() { 
     /* stuff */ 
     deferred.reject(); // as the last step, reject the deferred, there was a failure 
    }); 

    return deferred.promise; 
} 

然後,當你去打電話verifyAccessToken你會做這樣的事情:

/* stuff before the verifyAccessToken call */ 
verifyAccessToken().then(
    function() { 
     /* any stuff after the verifyAccessToken call */ 
     /* or any code that was dependent on verifying the access token */ 
    }, 
    function() { 
     /* code to handle a failure of renewing the token */ 
    }); 
/* 
    there should be nothing after the call that depends on verifying the 
    access token. Remember this asynchronous so the initial call to verifyAccessToken 
    is going to return immediately. Then sometime in the future the success 
    or error call back will be called. 
*/