Вопрос по javascript, jquery, ajax – Как лучше всего повторить запрос AJAX при сбое с помощью jQuery?

89

Псевдокод:

$(document).ajaxError(function(e, xhr, options, error) {
  xhr.retry()
})

Еще лучше было бы какое-то экспоненциальное отступление

Я не уверен, что это лучший способ, так что просто комментарий, но если вы вызываете свой ajax из функции, вы можете дать ему параметрtriesи при неудаче вы вызываете свою функцию сtries+1, Остановить исполнение наtries==3 или любой другой номер. Nanne
Хорошее решение здесь:stackoverflow.com/questions/6298612/… Jeremy A. West
возможный дубликатRetry a jquery ajax request which has callbacks attached to its deferred user2284570

Ваш Ответ

7   ответов
0

https://github.com/execjosh/jquery-ajax-retry

Автоматическое увеличение таймаута было бы хорошим дополнением к нему.

Чтобы использовать его глобально, просто создайте свою собственную функцию с подписью $ .ajax, используйте там retry api и замените все ваши вызовы $ .ajax новой функцией.

Также вы можете напрямую заменить $ .ajax, но вы не сможете делать вызовы xhr без повторных попыток.

Error: User Rate Limit Exceeded
7

One approach is to use a wrapper function:

(function runAjax(retries, delay){
  delay = delay || 1000;
  $.ajax({
    type        : 'GET',
    url         : '',
    dataType    : 'json',
    contentType : 'application/json'
  })
  .fail(function(){
    console.log(retries); // prrint retry count
    retries > 0 && setTimeout(function(){
        runAjax(--retries);
    },delay);
  })
})(3, 100);

Another approach would be to use a retries property on the $.ajax

// define ajax settings
var ajaxSettings = {
  type        : 'GET',
  url         : '',
  dataType    : 'json',
  contentType : 'application/json',
  retries     : 3  //                 <-----------------------
};

// run initial ajax
$.ajax(ajaxSettings).fail(onFail)

// on fail, retry by creating a new Ajax deferred
function onFail(){
  if( ajaxSettings.retries-- > 0 )
    setTimeout(function(){
        $.ajax(ajaxSettings).fail(onFail);
    }, 1000);
}

Another way (GIST) - override original $.ajax (better for DRY)

// enhance the original "$.ajax" with a retry mechanism 
$.ajax = (($oldAjax) => {
  // on fail, retry by creating a new Ajax deferred
  function check(a,b,c){
    var shouldRetry = b != 'success' && b != 'parsererror';
    if( shouldRetry && --this.retries > 0 )
      setTimeout(() => { $.ajax(this) }, this.retryInterval || 100);
  }

  return settings => $oldAjax(settings).always(check)
})($.ajax);



// now we can use the "retries" property if we need to retry on fail
$.ajax({
    type          : 'GET',
    url           : 'http://www.whatever123.gov',
    timeout       : 2000,
    retries       : 3,     //       <-------- Optional
    retryInterval : 2000   //       <-------- Optional
})
// Problem: "fail" will only be called once, and not for each retry
.fail(()=>{
  console.log('failed') 
});

Нужно учестьsure $.ajax метод не был уже упакован ранее, чтобы избежать повторения одного и того же кода дважды.


Вы можете скопировать и вставить эти фрагменты (как есть) в консоль, чтобы протестировать их

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
0

который работал для меня для асинхронной загрузки библиотек:

var jqOnError = function(xhr, textStatus, errorThrown ) {
    if (typeof this.tryCount !== "number") {
      this.tryCount = 1;
    }
    if (textStatus === 'timeout') {
      if (this.tryCount < 3) {  /* hardcoded number */
        this.tryCount++;
        //try again
        $.ajax(this);
        return;
      }
      return;
    }
    if (xhr.status === 500) {
        //handle error
    } else {
        //handle error
    }
};

jQuery.loadScript = function (name, url, callback) {
  if(jQuery[name]){
    callback;
  } else {
    jQuery.ajax({
      name: name,
      url: url,
      dataType: 'script',
      success: callback,
      async: true,
      timeout: 5000, /* hardcoded number (5 sec) */
      error : jqOnError
    });
  }
}

Тогда просто позвони.load_script из вашего приложения и вложите ваш успех обратного вызова:

$.loadScript('maps', '//maps.google.com/maps/api/js?v=3.23&libraries=geometry&libraries=places&language=&hl=&region=', function(){
    initialize_map();
    loadListeners();
});
4

Я имел большой успех с этим кодом ниже (пример:http://jsfiddle.net/uZSFK/)

$.ajaxSetup({
    timeout: 3000, 
    retryAfter:7000
});

function func( param ){
    $.ajax( 'http://www.example.com/' )
        .success( function() {
            console.log( 'Ajax request worked' );
        })
        .error(function() {
            console.log( 'Ajax request failed...' );
            setTimeout ( function(){ func( param ) }, $.ajaxSetup().retryAfter );
        });
}
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededapi.jquery.com/jQuery.ajaxSetup
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
203

Что-то вроде этого:


$.ajax({
    url : 'someurl',
    type : 'POST',
    data :  ....,   
    tryCount : 0,
    retryLimit : 3,
    success : function(json) {
        //do something
    },
    error : function(xhr, textStatus, errorThrown ) {
        if (textStatus == 'timeout') {
            this.tryCount++;
            if (this.tryCount <= this.retryLimit) {
                //try again
                $.ajax(this);
                return;
            }            
            return;
        }
        if (xhr.status == 500) {
            //handle error
        } else {
            //handle error
        }
    }
});
Error: User Rate Limit ExceededtryCountError: User Rate Limit ExceededretryLimitError: User Rate Limit Exceededthis.retryLimit--; if (this.retryLimit) { ... $.ajax(this) ... }
Error: User Rate Limit Exceededgithub.com/mberkom/jQuery.retryAjax
Error: User Rate Limit Exceeded.successError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
0

поскольку в функции ошибки он указывает на Window. (И такой способ использования «this» недостаточно безопасен, поскольку вы не знаете, как они реализуют Ajax, или нет необходимости.)

Для Zepto, может быть, вы могли бы попробовать ниже, до сих пор это работает хорошо для меня:

var AjaxRetry = function(retryLimit) {
  this.retryLimit = typeof retryLimit === 'number' ? retryLimit : 0;
  this.tryCount = 0;
  this.params = null;
};
AjaxRetry.prototype.request = function(params, errorCallback) {
  this.tryCount = 0;
  var self = this;
  params.error = function(xhr, textStatus, error) {
    if (textStatus === 'timeout') {
      self.tryCount ++;
      if (self.tryCount <= self.retryLimit) {
        $.ajax(self.params)      
        return;
      }
    }
    errorCallback && errorCallback(xhr, textStatus, error);
  };
  this.params = params;
  $.ajax(this.params);
};
//send an ajax request
new AjaxRetry(2).request(params, function(){});

Используйте конструктор, чтобы убедиться, что запрос реентерабелен!

0

.done() после их вызова ajax, потому что у вас не будет метода успешной привязки к будущему обратному вызову. Так что, если кто-то делает это:

$.ajax({...someoptions...}).done(mySuccessFunc);

затемmySuccessFunc не будет вызван при повторной попытке. Вот мое решение, которое в значительной степени заимствовано из ответа @ cjpak.Вот, В моем случае я хочу повторить попытку, когда шлюз API AWS отвечает с ошибкой 502.

const RETRY_WAIT = [10 * 1000, 5 * 1000, 2 * 1000];

// This is what tells JQuery to retry $.ajax requests
// Ideas for this borrowed from https://stackoverflow.com/a/12446363/491553
$.ajaxPrefilter(function(opts, originalOpts, jqXHR) {
  if(opts.retryCount === undefined) {
    opts.retryCount = 3;
  }

  // Our own deferred object to handle done/fail callbacks
  let dfd = $.Deferred();

  // If the request works, return normally
  jqXHR.done(dfd.resolve);

  // If the request fails, retry a few times, yet still resolve
  jqXHR.fail((xhr, textStatus, errorThrown) => {
    console.log("Caught error: " + JSON.stringify(xhr) + ", textStatus: " + textStatus + ", errorThrown: " + errorThrown);
    if (xhr && xhr.readyState === 0 && xhr.status === 0 && xhr.statusText === "error") {
      // API Gateway gave up.  Let's retry.
      if (opts.retryCount-- > 0) {
        let retryWait = RETRY_WAIT[opts.retryCount];
        console.log("Retrying after waiting " + retryWait + " ms...");
        setTimeout(() => {
          // Retry with a copied originalOpts with retryCount.
          let newOpts = $.extend({}, originalOpts, {
            retryCount: opts.retryCount
          });
          $.ajax(newOpts).done(dfd.resolve);
        }, retryWait);
      } else {
        alert("Cannot reach the server.  Please check your internet connection and then try again.");
      }
    } else {
      defaultFailFunction(xhr, textStatus, errorThrown); // or you could call dfd.reject if your users call $.ajax().fail()
    }
  });

  // NOW override the jqXHR's promise functions with our deferred
  return dfd.promise(jqXHR);
});

Этот фрагмент будет отключен и повторен через 2 секунды, затем 5 секунд, затем 10 секунд, которые вы можете редактировать, изменив константу RETRY_WAIT.

Служба поддержки AWS предложила добавить повтор, поскольку это происходит для нас только один раз в голубой луне.

Похожие вопросы