2013-09-05 33 views
29

Tôi đã tạo một trình chặn trong ứng dụng phát hiện mất mát phiên (máy chủ gửi một HTTP 419). Trong trường hợp này, tôi cần phải yêu cầu một phiên mới từ máy chủ, và sau đó tôi muốn gửi lại yêu cầu ban đầu một cách tự động.
Có lẽ tôi có thể lưu yêu cầu trong bộ chặn đánh chặn yêu cầu và sau đó gửi lại, nhưng có thể có giải pháp đơn giản hơn.Làm cách nào để gửi yêu cầu lại trong bộ chặn phản hồi?

Lưu ý rằng tôi phải sử dụng một dịch vụ web cụ thể để tạo phiên.

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'); 
    }); 

Trả lời

21

Đây là giải pháp của tôi khi sử dụng lời hứa cho những người quan tâm. Về cơ bản bạn cần phải yêu cầu một phiên mới, và chờ phản hồi trước khi gửi một yêu cầu mới tương ứng với yêu cầu ban đầu (sử dụng response.config). Bằng cách trả lại lời hứa $ http (response.config), bạn đảm bảo rằng phản hồi sẽ được xử lý như thể đó là yêu cầu ban đầu.
(cú pháp có thể không phải là tốt nhất như tôi mới vào lời hứa)

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

Một lưu ý cho bất kỳ ai nhìn vào điều này ngày hôm nay: Cú pháp của Angular cho interceptor đã thay đổi kể từ v1.1.x. Các giải pháp cho câu hỏi là tương tự, nhưng người ta sẽ thấy ở đây cho cú pháp mới hơn: https://docs.angularjs.org/api/ng/service/$http#interceptors –

+0

Đây là một phiên bản đơn giản của điều này: http://stackoverflow.com/a/31965945/651556 – Sushil

5

Bạn đang đi đúng hướng, về cơ bản bạn lưu yêu cầu vào hàng đợi và thử lại sau khi bạn đã thiết lập lại phiên.

Kiểm tra mô-đun phổ biến này: http xác thực góc (https://github.com/witoldsz/angular-http-auth). Trong mô-đun này, họ chặn 401 phản hồi nhưng bạn có thể mô hình hóa giải pháp của mình theo cách tiếp cận này.

+0

nhờ Ok for the link nó là thú vị. Có vẻ như $ http (response.config) đang hoạt động. Tôi sẽ kiểm tra điều đó. – D0m3

3

Nhiều hơn hoặc ít hơn cùng một giải pháp, dịch trong nguyên cảo:

/// <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) 
    }]); 

Hope trợ giúp này.

17

Phương pháp responseError của httpInterceptor phải như thế này:

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; 
    } 
    } 
} 

Và sự kỳ diệu xảy ra ở đây:

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

Cảm ơn bạn đã thực hiện một ngày của tôi! –

+0

Rực rỡ, cảm ơn bạn. – brazorf

Các vấn đề liên quan