2013-09-05 6 views
29

मैंने अपने आवेदन में एक इंटरसेप्टर बनाया है जो सत्र हानि का पता लगाता है (सर्वर HTTP 41 9 भेजता है)। इस मामले में, मुझे सर्वर से नए सत्र का अनुरोध करने की आवश्यकता है, और फिर मैं मूल अनुरोध को स्वचालित रूप से भेजना चाहता हूं।
शायद मैं अनुरोध इंटरसेप्टर में अनुरोध को सहेज सकता हूं, और फिर इसे फिर से भेज सकता हूं, लेकिन एक आसान समाधान हो सकता है।प्रतिक्रिया इंटरसेप्टर में मैं फिर से अनुरोध कैसे भेज सकता हूं?

ध्यान दें कि मुझे सत्र बनाने के लिए एक विशिष्ट webservice का उपयोग करना है।

angular.module('myapp', [ 'ngResource' ]).factory(
    'MyInterceptor', 
    function ($q, $rootScope) { 
     return function (promise) { 
      return promise.then(function (response) { 
       // do something on success 
       return response; 
      }, function (response) { 
       if(response.status == 419){ 
        // session lost 
        // create new session server-side 
        // Session.query(); 
        // then send current request again 
        // ??? 
       } 
       return $q.reject(response); 
      }); 
     }; 
    }).config(function ($httpProvider) { 
     $httpProvider.responseInterceptors.push('MyInterceptor'); 
    }); 

उत्तर

21

यहां रुचि रखने वालों के लिए वादे का उपयोग करके मेरा समाधान है। असल में आपको एक नए सत्र का अनुरोध करने की आवश्यकता है, और मूल अनुरोध (प्रतिक्रिया.config का उपयोग करके) के साथ एक नया अनुरोध भेजने से पहले प्रतिक्रिया की प्रतीक्षा करें। वादा $ http (respond.config) को वापस लौटने से आप सुनिश्चित करते हैं कि प्रतिक्रिया का इलाज किया जाएगा जैसे कि यह मूल अनुरोध था।
(सिंटेक्स सबसे अच्छा नहीं हो सकता है के रूप में मैं वादे करने के लिए नए कर रहा हूँ)

angular.module('myapp', [ 'ngResource' ]).factory(
    'MyInterceptor', 
    function ($q, $rootScope) { 
     return function (promise) { 
      return promise.then(function (response) { 
       // do something on success 
       return response; 
      }, function (response) { 
       if(response.status == 419){ 
        // session lost 
        var Session = $injector.get('Session'); 
        var $http = $injector.get('$http'); 
        // first create new session server-side 
        var defer = $q.defer(); 
        var promiseSession = defer.promise; 
        Session.query({},function(){ 
         defer.resolve(); 
        }, function(){ 
         // error 
         defer.reject(); 
        });  
        // and chain request 
        var promiseUpdate = promiseSession.then(function(){ 
         return $http(response.config); 
        }); 
        return promiseUpdate; 
       } 
       return $q.reject(response); 
      }); 
     }; 
    }).config(function ($httpProvider) { 
     $httpProvider.responseInterceptors.push('MyInterceptor'); 
    }); 
+0

आज इसे देखने वाले किसी के लिए एक नोट: v1.1.x के बाद से इंटरसेप्टर के लिए कोणीय का वाक्यविन्यास बदल गया है। प्रश्न का समाधान समान है, लेकिन किसी को नए सिंटैक्स के लिए यहां देखना चाहिए: https://docs.angularjs.org/api/ng/service/$http#interceptors –

+0

यहां इसका एक सरल संस्करण है: http://stackoverflow.com/a/31965945/651556 – Sushil

5

आप सही रास्ते पर हैं, आप मूल रूप से अनुरोध को कतार में संग्रहीत करते हैं और सत्र को फिर से स्थापित करने के बाद पुनः प्रयास करते हैं।

इस लोकप्रिय मॉड्यूल को देखें: कोणीय http auth (https://github.com/witoldsz/angular-http-auth)। इस मॉड्यूल में, वे 401 प्रतिक्रियाओं को रोकते हैं लेकिन आप इस समाधान के अपने समाधान को मॉडल कर सकते हैं।

+0

लिंक यह दिलचस्प है के लिए ठीक है, धन्यवाद। ऐसा लगता है कि $ http (response.config) काम कर रहा है। मैं इसका परीक्षण करने जा रहा हूं। – D0m3

3

कमोबेश एक ही समाधान है, टाइपप्रति में अनुवाद:

/// <reference path="../app.ts" /> 
/// <reference path="../../scripts/typings/angularjs/angular.d.ts" /> 

class AuthInterceptorService { 

    static serviceId: string = "authInterceptorService"; 

    constructor(private $q: ng.IQService, private $location: ng.ILocationService, private $injector, private $log: ng.ILogService, private authStatusService) {} 

    // Attenzione. Per qualche strano motivo qui va usata la sintassi lambda perché se no ts sbrocca il this. 
    public request = (config: ng.IRequestConfig) => { 

     config.headers = config.headers || {}; 

     var s: AuthStatus = this.authStatusService.status; 
     if (s.isAuth) { 
      config.headers.Authorization = 'Bearer ' + s.accessToken; 
     } 

     return config; 
    } 

    public responseError = (rejection: ng.IHttpPromiseCallbackArg<any>) => { 

     if (rejection.status === 401) { 

      var that = this; 

      this.$log.warn("[AuthInterceptorService.responseError()]: not authorized request [401]. Now I try now to refresh the token."); 

      var authService: AuthService = this.$injector.get("authService"); 
      var $http: ng.IHttpService = this.$injector.get("$http"); 

      var defer = this.$q.defer(); 
      var promise: ng.IPromise<any> = defer.promise.then(() => $http(rejection.config)); 

      authService 
       .refreshAccessToken() 
        .then((response) => { 

         that.$log.info("[AuthInterceptorService.responseError()]: token refreshed succesfully. Now I resend the original request."); 

         defer.resolve(); 
        }, 
        (err) => { 

         that.$log.warn("[AuthInterceptorService.responseError()]: token refresh failed. I need to logout, sorry..."); 

         this.authStatusService.clear(); 
         this.$location.path('/login'); 
        }); 

      return promise; 
     } 

     return this.$q.reject(rejection); 
    } 
} 

// Update the app variable name to be that of your module variable 
app.factory(AuthInterceptorService.serviceId, 
    ["$q", "$location", "$injector", "$log", "authStatusService", ($q, $location, $injector, $log, authStatusService) => { 
     return new AuthInterceptorService($q, $location, $injector, $log, authStatusService) 
    }]); 

आशा इस मदद करते हैं।

17

httpInterceptor की responseError विधि इस तरह होना चाहिए:

responseError: function (response) { 
    // omit the retry if the request is made to a template or other url 
    if (response.config.apiCal === true) { 
    if (response.status === 419) { 
     var deferred = $q.defer(); 
     // do something async: try to login.. rescue a token.. etc. 
     asyncFuncionToRecoverFrom419(funcion(){ 
     // on success retry the http request 
     retryHttpRequest(response.config, deferred); 
     }); 
     return deferred.promise; 
    } else { 
     // a template file... 
     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); 
} 
+0

धन्यवाद आपने मेरा दिन बनाया! –

+0

शानदार, धन्यवाद। – brazorf

संबंधित मुद्दे

 संबंधित मुद्दे