Подтвердить что ты не робот

Запрос повторной попытки с перехватчиком $http

Я уверен, что есть простой способ сделать то, что я хочу, я просто наклоняю голову вокруг него. Как я могу получить http-перехватчик в angular, чтобы повторить запрос, если он терпит неудачу? Полагаю, мне нужно было бы выполнить какое-то обещание в запросе? Тогда в ответе мне нужно было бы проверить, был ли ответ ошибкой, и если да, выполняйте обещание? Как это делается? Я пытаюсь приспособить пример здесь: http://docs.angularjs.org/api/ng.$http

Причина, по которой я пытаюсь использовать перехватчик, заключается в том, что мне нужно добавить токен и еще несколько вещей в URL-адрес запроса, а также некоторые вещи для обработки xdr.

4b9b3361

Ответ 1

Здесь перехватчик $http, который (немедленно) повторяет запрос времени ожидания (то есть статус ответа 0). Для создания этого примера было два неочевидных элемента (для меня!):

  • Как вызвать $http изнутри перехватчика - просто добавление $http в список зависимостей не работает как angular жалуется на круговую зависимость
  • Как ссылаться на исходный запрос из объекта ответа, чтобы повторить его.

Этот ответ затрагивает обе темы, но более активен, поэтому я включаю упрощенную версию ниже.

joinApp.factory('httpResponseErrorInterceptor',function($q, $injector) {
  return {
    'responseError': function(response) {
      if (response.status === 0) {
        // should retry
        var $http = $injector.get('$http');
        return $http(response.config);
      }
      // give up
      return $q.reject(response);
    }
  };
});

joinApp.config(function($httpProvider) {
  $httpProvider.interceptors.push('httpResponseErrorInterceptor');
});

В вашей реальной реализации вам, скорее всего, понадобится более сложная обработка кода ответа HTTP, ограничение количества повторных попыток и т.д.

Ответ 2

Для полноты, вот версия mygzi answer с задержкой повтора:

.factory('httpResponseErrorInterceptor', ['$injector', '$q', '$timeout', function($injector, $q, $timeout) {
  return {
    'responseError': function(response) {
      if (response.status === 0) {
        return $timeout(function() {
          var $http = $injector.get('$http');
          return $http(response.config);
        }, 15000);
      }
      return $q.reject(response);
    }
  };
}])

.config(function($httpProvider) {
  $httpProvider.interceptors.push('httpResponseErrorInterceptor');
});

$timeout возвращает обещание, которое завершается тем, что возвращается из параметра функции, поэтому мы можем просто просто вернуть вызов $http, завернутый в $timeout.

Ответ 3

Я сделал это для приложения, которое я написал раньше. Чтобы повторить попытку, используйте функцию $http в функции (или, предпочтительно, в сервисе, чтобы вы могли легко ее использовать). Если запрос не удался, снова вызовите функцию.

Трюк заключается в том, чтобы передать объект обещания вместе с каждым запросом. Если вы создадите новое обещание с каждым запросом, оно не будет соответствовать тому, которое вы вернули первоначальному абоненту, поэтому первоначальный вызывающий абонент не сможет решить свое обещание после того, как запрос пройдет.

Итак, это что-то вроде этого (обратите внимание, что объект-отложенный передается в каждой попытке):

app.service('HttpService', ['$q', function($q) {
  this.makeRequest = _makeRequest;

  function _makeRequest(url, data, deffered) {
    // We want to keep the same promise for each request, so we don't loose track
    if (deferred === undefined) {
      deferred = $q.defer();
    }

    // Now make the request
    $http({...}).success(...).error(
      function(){
        // If some condition
        _makeRequest(url, data, deffered);
      }
    )

    // Lastly return the promise
    return deferred.promise;
  }
}])