web-dev-qa-db-fra.com

Comment rappeler une fonction sur 404 dans une requête JSON ajax avec jQuery? 

Je veux faire une demande Ajax avec une réponse en JSON. J'ai donc fait cette demande Ajax:

$.ajax({
    url: 'http://my_url',
    dataType: "json",
    success: function(data){
      alert('success');
    },
    error: function(data){
      alert('error');
    },
    complete: function(data) {
      alert('complete')
    }})

Ce code fonctionne bien, mais lorsque mon URL m'envoie un code HTTP 404, aucun rappel n'est utilisé, même le rappel complet. Après des recherches, c’est parce que mon type de données est «json», donc que 404 renvoie un code HTML et que l’analyse JSON a échoué. Donc pas de rappel.

Avez-vous une solution pour appeler une fonction de rappel lorsqu'un 404 est levé?

EDIT: le rappel complet n'est pas appelé. 404. Si vous souhaitez une URL avec 404, vous pouvez appeler: http://Twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697 c'est avec cette URL que j'ai mon problème.

21
shingara
$.ajax({
    url: 'http://Twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697',
    dataType: "json",
    success: function(data) {
        alert('success');
    },
    error: function(data) {
        alert('error');
    },
    complete: function(xhr, data) {
        if (xhr.status != 0)
             alert('success');
        else
             alert('fail');
    }
})
19
Dustin Laine

Avec votre configuration, jQuery utilise jsonp pour transporter les données. Cela fonctionne en insérant dynamiquement un élément de script et en définissant l'URL sur la valeur spécifiée. Les données renvoyées par le serveur sont ensuite évaluées en tant que JavaScript - appelant généralement le rappel fourni. Si le serveur retourne un 404, le contenu n'est évidemment pas JavaScript et le rappel n'est jamais appelé. Certains navigateurs prennent en charge les gestionnaires d’erreurs sur la balise de script, qui sont appelés dans ces situations. Malheureusement, IE ne supporte pas cela. Le meilleur moyen de détecter une erreur est de s’appuyer sur un délai d’attente.

Dans votre cas, vous devez spécifier une option timeout supplémentaire, ce qui entraîne l'appel du gestionnaire d'erreurs si le rappel n'a pas été appelé à temps (ce qui serait le cas d'une réponse 404).

$.ajax({
  url: 'http://my_url',
  timeout: 2000, // 2 seconds timeout
  dataType: "json",
  success: function(data){
    alert('success');
  },
  error: function(data){
    alert('error');
  },
  complete: function(data) {
    alert('complete')
  }
});
9
Fabian Jakobs

Si vous souhaitez gérer les erreurs lors de l'accès à l'API Twitter avec Javascript et jsonp, vous devez inclure le paramètre suppress_response_codes dans votre demande. Ainsi, toutes les réponses de l'API Twitter répondent avec une réponse 200 OK et incluent une erreur. Ensuite, vous devez vérifier si la réponse inclut le paramètre error ou non.

$.ajax({
  url: "https://api.Twitter.com/1/users/show.json",
  dataType: 'jsonp',
  jsonp: "callback",
  data: {
    screen_name: "simongate1337",
    suppress_response_codes: true // <- Important part
  },
  success: function(data) {
    if(data.error) {
      console.log("ERROR: "+data.error);
    } else {
      console.log("Success, got user " + data.screen_name);
    }
  }
});
4
Simon Gate

Utilisez l'option statusCode-

$.ajax({
    url: 'http://my_url',
    dataType: "json",
    statusCode: {
        404: function() {
            alert("I could not find the information you requested.");
        }
    },
    success: function(data) {
      alert('success');
    },
    error: function(data) {
      alert('error');
    },
    complete: function(data) {
      alert('complete');
    }
})
3
Peter Rader

Ne pensez-vous pas que le problème ne vient pas du type de données mais des requêtes interdomaines que vous n'êtes pas autorisé à faire?

Le code ci-dessous fonctionne comme prévu lorsque vous demandez des données du même domaine, mais pas lorsque vous effectuez des demandes entre domaines:

function handle404(xhr){
    alert('404 not found');
}

function handleError(xhr, status, exc) {
     // 0 for cross-domain requests in FF and security exception in IE 
    alert(xhr.status);
    switch (xhr.status) {
        case 404:
            handle404(xhr);
            break;
    }
}

function dumbRequest() {
    var url = 'http://Twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697';
    url = 'http://Twitter.com/';    
    url = '/mydata.json';    
//    url = 'mydata.json';    
    $.ajax(
        {url: url,
         dataType: 'json',
         error: handleError}
    );
}
2
newtover

Savez-vous que même si le statut HTTP est 404, le corps réel est un fichier JSON valide? Par exemple, ce lien a le JSON suivant:

jsonp1269278524295({"request":"/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697","error":"Not found"})

En tant que tel, vous devriez vérifier si vos données ont la propriété error dans votre fonction de rappel normale.

UPDATE: apparemment, même si le contenu réel de la page est un JSON valide, le navigateur (j'ai vérifié dans Firefox) ne l'exécute pas, probablement parce qu'il s'agit d'un 404. JQuery doit ajouter un élément script (en raison du problème entre domaines), son encapsuleur JSONP n'est jamais appelé et, par conséquent, vos rappels ne le sont pas non plus.

En bref, je ne pense pas qu'il soit possible de régler ce problème sans ajouter manuellement cet élément de script et vérifier si votre fonction de rappel prédéfinie a été appelée par la suite.

1
janmoesen

Juste face au même problème, et a vu une autre question a mentionné que jQuery-JSONP (plugin jQuery) prend en charge la capture d’erreurs 404 ou comme ils le décrivent: " récupération d’erreur en cas de défaillance réseau réponses JSON formées "

Et ça marche parfait :)

Voici mon code (simplifié) pour récupérer des détails sur une vidéo YouTube via JSONP:

$.jsonp(
{
    url: "https://gdata.youtube.com/feeds/api/videos/ee925OTFBCA",
    callbackParameter: "callback",
    data: 
    {
        alt: "jsonc-in-script",
        v: "2"
    },
    success: function(json, textStatus) 
    { 
        console.log("WEEEEEEEE!"); 
    },
    error: function(xOptions, textStatus) 
    {
        console.error(arguments);
    }
});
1
Mark

Est-ce simplement parce que la dataType est définie sur "json"? Si tel est le cas, essayez de le remplacer par text et évaluez vous-même le JSON:

$.ajax({
    url: 'http://Twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697',
    dataType: 'text',
    success: function(data, status, xmlHttp) {
        try {
            data = eval('(' + data + ')');
            alert('success');
        } catch (e) {
            alert('json parse error');
        }
    },
    error: function(xmlHttp, status, error) {
        alert('error');
    },
    complete: function(xmlHttp, status) {
        alert('complete');
    }
});
1
Matt Huggins

Voici comment je traite avec cela. Je vérifie les données renvoyées pour les erreurs avant d'essayer de les utiliser. Ce qui est montré ci-dessous est juste un exemple que vous pourriez étendre pour correspondre plus étroitement à vos besoins. Cela prend également en compte les temps morts de session et autres scénarios ...

Mon appel initial:

  $.ajax({ type: 'POST', 
    url: '../doSomething',
    data: 'my data',
    success: function(data) {
      if (HasErrors(data)) return;
      var info = eval('(' + data + ')');
      // do what you want with the info object
    },
    error: function(xmlHttpRequest) {
      ReportFailure(xmlHttpRequest);
    }
  });

Et les deux fonctions d'assistance:

function HasErrors(data) {
  if (data.search(/login\.aspx/i) != -1) {
    // timed out and being redirected to login page!
    top.location.href = '../login.aspx';
    return true;
  }
  if (data.search(/Internal Server Error/) != -1) {
    ShowStatusFailed('Server Error.');
    return true;
  }
  if (data.search(/Error.aspx/) != -1) {
    // being redirected to site error reporting page...
    ShowStatusFailed('Server Error. Please try again.');
    return true;
  }
  return false;
}

et

function ReportFailure(msg) {
  var text;
  if (typeof msg == 'string') {
    text = msg;
  }
  else if (typeof msg.statusText == 'string') {
    if (msg.status == 200) {
      text = msg.responseText;
    }
    else {
      text = '(' + msg.status + ') ' + msg.statusText + ': ';
      // use the Title from the error response if possible
      var matches = msg.responseText.match(/\<title\>(.*?)\<\/title\>/i);
      if (matches != null)
      { text = text + matches[1]; }
      else
      { text = text + msg.responseText; }
    }
  }
  // do something in your page to show the "text" error message
  $('#statusDisplay')
    .html('<span class="ui-icon ui-icon-alert"></span>' + text)
    .addClass('StatusError');
}
0
Glen Little

La solution suivante fonctionne bien pour moi :)

$.ajax({
    url: 'http://my_url',
    dataType: "json",
    success: function(data){
      alert('success');
    },
    error: function(data){
      alert('error');
    },complete: function(xhr, data) {
        if(data==="parsererror"){
             alert('404');
        }
    } 
});
0
Awan