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

Определение того, отменен ли AJAX или получена ошибка в перехватчике AngularJs

У меня есть "аннулируемый" angularJs $http вызов следующим образом:

var defer = $q.defer()
$http.post("http://example.com/someUrl", {some: "data"}, {timeout: defer.promise})

И я отменяю этот запрос ajax, используя defer.resolve(), потому что это требует некоторая логика.


Где-то где-то в моем коде, у меня есть итератор вроде этого:

angular.module("services.interceptor", arguments).config(function($httpProvider) {
     $httpProvider.interceptors.push(function($q) {
        return {
          responseError: function(rejection) {
            if(rejection.status == 0) {
              alert("check your connection");
            }
           return $q.reject(rejection);
        }
      };
    });
  });
});

Проблема:

Если есть проблема подключения к Интернету , ajax не работает со статусом 0, а перехватчик поймает его. Если ajax отменяется с помощью ожидания времени ожидания, чем статус также 0, а перехватчик поймает его.

Я не могу узнать, отменено или получено сообщение об ошибке в обработчике responseError.

Мой наивный подход заключается в том, чтобы проверить, задан ли тайм-аут следующим образом:

responseError: function(rejection) {
  if(rejection.status == 0 && !rejection.config.timeout) {
    alert("check your connection");
  }
  return $q.reject(rejection);
}

Это только гарантирует, что есть условие таймаута для этого запроса, а не , из-за которого оно не получилось. Но это лучше, чем ничего.

Есть ли действительно эффективный способ определения того, был ли ajax поврежден или отменен?

Я использую AngularJs 1.1.5

4b9b3361

Ответ 1

Я закончил это с помощью флага, который проверяется в обработчике ошибок.

Я начал следовать рекомендациям в конце этой проблемы AngularJS Github: https://github.com/angular/angular.js/issues/1159#issuecomment-25735438

Это привело меня к созданию службы, которая использовала обещание вручную "тайм-аут" вызова http - как вы это делали ниже - путем копирования связанного плунга из этой проблемы: http://plnkr.co/edit/P8wKns51GVqw5mwS5l5R?p=preview

Но это было не совсем полным, так как это не затрагивало проблему, которую вы подняли; в обработке ошибок, как определить, был ли вызов подлинным отключением/тайм-аутом сервера, или просто тайм-аут с ручным запуском. В конце концов, мне пришлось прибегнуть к его сохранению в другой переменной (подобно обещанию тайм-аута), который можно увидеть в этом плунге: http://plnkr.co/edit/BW6Zwu

Основной метод этого кода выглядит следующим образом

return function (url) {
    var cancelQuery = null;
    var queryCancelled = false;

    return function runQuery(query) {
      if (cancelQuery) {
        queryCancelled = true;
        cancelQuery.resolve();
      }
      cancelQuery = $q.defer();
      return $http.
        get(url, { params: { query: query }, timeout: cancelQuery.promise }).
        then(function (response) {
          cancelQuery = null;
          return response.data;
        }, function (error) {
          if(queryCancelled) {
            console.log("Request cancelled");
            queryCancelled = false;
          } else {
            console.log("Actual Error !");
          }
        });
    };
  };

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

Ответ 2

Если вы отмените запрос с помощью timeout, таймаут будет указан в конфигурации ответа.

Проверьте .config.timeout в объекте ответа:

function config($httpProvider) {

    $httpProvider.interceptors.push(function ($q, $injector) {
        return {
            request: function (config) {
                return config;
            },

            response: function (response) {
                return response || $q.when(response);
            },

            responseError: function (response) {
                switch (response.status) {
                    case -1:
                    case 500 :
                    case 501 :
                    case 502 :
                    case 503 :
                    case 504 :
                        // the webapp sometimes aborts network requests. Those that dropped should not be restarted
                        if (response.status === -1 && response.config.timeout) {
                            break;
                        }
                        return retryRequest(response.config, response.status);
                }
                // otherwise
                return $q.reject(response);
            }
        };
    });
}

Ответ 3

Я знаю, что вопрос уже немного старше, но я натолкнулся на его поиск решения для той же проблемы. Кроме того, что в ответе уже дано, я не хочу проверять флаг, который я установил одновременно с тем, что я искал запрос AJAX. Это может быть уже новый запрос, который не был отменен.

Итак, я нашел для меня другое решение. Возможно, кто-то может его использовать, тем не менее, это не актуальный вопрос.

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

var defer = $q.defer()
$http.get("http://example.com/someUrl", {timeout: defer.promise})
  .error(function(data, status){
      if (data === null && status === 0) {
          // the request was cancled
      }
   });

Ответ 4

Вы можете использовать (rejection.config.timeout.status!= 499):

...timeout.promise.status = 499;
...timeout.resolve();

responseError: function(rejection) {
  if(rejection.status == 0 && rejection.config.timeout.status != 499) {
    alert("check your connection");
  }
  return $q.reject(rejection);
}

вместо:

responseError: function(rejection) {
  if(rejection.status == 0 && !rejection.config.timeout) {
    alert("check your connection");
  }
  return $q.reject(rejection);
}

Кстати, в этом случае вам не нужен дополнительный декоратор запросов.

Ответ 5

Мне удалось определить, был ли запрос отменен в Chrome v55, проверив тип свойства глобального объекта события на строку "abort" (код ниже). У меня возникла проблема, что текущие запросы были отменены при переходе на другую страницу и вызвали ответError.

angular.module("services.interceptor", arguments)
  .config(function($httpProvider) {
     $httpProvider.interceptors.push(function($q, $window) {
        return {
          responseError: function(rejection) {
            if($window.event.type === "abort") {
               // handle cancelled here
            } else if(rejection.status < 1) {
              alert("check your connection");
            }
           return $q.reject(rejection);
        }
      };
    });
  });
});

(также: свойство состояния, похоже, изменилось с 0 на -1 на сетевые ошибки, поэтому я написал rejection.status < 1))