2013-08-15 2 views
13

У меня есть «сократимых» angularJs $http вызов, как это:Определение, если AJAX отменен или есть ошибка в AngularJs перехватчик

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

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


Некоторые где-то в моем коде, у меня есть iterceptor так:

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

Проблема:

Если есть интернет проблема соединения, Аякса терпит неудачу со статусом 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

+0

Вы можете получить код статуса HTTP? –

+0

@DavinTryon В обоих случаях код статуса отмены и сетевой ошибки возвращается как 0. –

+0

Как именно эта проблема на данный момент (с угловым 1.2.0) – Phantomwhale

ответ

5

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

Я начал по совету в конце этого 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 !"); 
      } 
     }); 
    }; 
    }; 

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

+1

Спасибо за подход. Я завернул мой $ http и данный cancelPromise, если таковые были с моими обещаниями, и проверил их статус, как вы делали в вашем примере, с помощью булевого флага. Чем я изменил исходный ответ .status = 0 к 1 для отмененных обещаний понять разницу. Благодаря! –

+1

Я сделал это немного более элегантным (по крайней мере, своим собственным), установив queryCancelled как свойство cancelQuery. Можно также использовать природу javascript. – Dave

0

Я знаю, что вопрос уже немного старше, но я натолкнулся на это, чтобы найти решение для той же проблемы.Кроме того, что в ответе уже дано, я не хочу проверять флаг, который я установил одновременно с тем, что я искал запрос 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 
     } 
    }); 
+6

ошибка таймаута из-за потерянного соединения также имеет данные null и статус 0 ... –

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); 
      } 
     }; 
    }); 
} 
+0

В моем случае, будет ли мой запрос отменен таймаутом или я получаю 401 с сервера, устанавливается response.config.timeout и response.status -1. – user276648

0

Вы можете использовать (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); 
} 

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

0

Мне удалось определить, был ли запрос отменен в 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))

Смежные вопросы