web-dev-qa-db-fra.com

XMLHttpRequest asynchrone ne fonctionne pas, renvoie toujours le statut

Voici un exemple XMLHttpRequest que j'ai bricolé à partir de w3schools

<html>
<head>
<script type="text/javascript">
function loadXMLDoc()
{
  var T="nothing";

  xmlhttp=new XMLHttpRequest();
  xmlhttp.overrideMimeType('text/plain');  // don't sc
  xmlhttp.onreadystatechange=function()
  {
    alert ("rdystate: " + xmlhttp.readyState);
    alert ("status: "   + xmlhttp.status);
    alert ("Text: "     + xmlhttp.statusText);
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
      T = xmlhttp.responseText;
    }
  }
xmlhttp.open("GET","SBL_PROBES.htm",true);
xmlhttp.send(null);
//T = xmlhttp.responseText;
alert(T);
}
</script>
</head>
<body>

<h2>Using the XMLHttpRequest object</h2>
<div id="myDiv"></div>
<button type="button" onclick="loadXMLDoc()">CHange Content</button>

</body>
</html>

XMLHttpRequest renvoie toujours un statut nul. 

Rien ne s'affiche dans la console d'erreur de Firefox.

Si je change la requête en synchrone en changeant de ligne

xmlhttp.open("GET","SBL_PROBES.htm",true);

à

xmlhttp.open("GET","SBL_PROBES.htm",false);

et commenter la ligne 

//T = xmlhttp.responseText;

Le texte du fichier demandé est renvoyé.

Le HTM et le fichier résident dans le même répertoire. Si vous essayez ceci, vous aurez besoin d’un fichier SBL_PROBES.htm également, son contenu n’est pas pertinent.

J'utilise Firefox 3.6.22.

Cela pourrait-il être un problème interdomaine? Si tel est le cas, pourquoi fonctionne-t-il comme une requête synchrone?

11
Mike D

Vous pouvez utiliser une fonction dans l'instruction if. Cette fonction est exécutée lorsque readystate passe à 4.

var handleResponse = function (status, response) {
   alert(response)
}
var handleStateChange = function () {
   switch (xmlhttp.readyState) {
      case 0 : // UNINITIALIZED
      case 1 : // LOADING
      case 2 : // LOADED
      case 3 : // INTERACTIVE
      break;
      case 4 : // COMPLETED
      handleResponse(xmlhttp.status, xmlhttp.responseText);
      break;
      default: alert("error");
   }
}
var xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=handleStateChange;
xmlhttp.open("GET","SBL_PROBES.htm",true);
xmlhttp.send(null);

Votre ancien code a passé un appel asynchrone et n’a continué que par la déclaration alert. T était vide à ce moment.

Ok, je vais expliquer un peu comment tout ça fonctionne:

Nous définissons d’abord deux fonctions de rappel, appelées plus tard dans la demande, nommées handleResponse et handleStateChange.

Ensuite, nous créons un objet, qui représente XMLHttpRequest.

var xmlhttp=new XMLHttpRequest();

Cela donne un objet comme suit (simplement):

XMLHttpRequest { status=0, readyState=0, multipart=false, onreadystatechange=handleEvent()}

Avec l'appel de la fonction open (...), vous définissez les paramètres de la requête:

xmlhttp.open("GET","SBL_PROBES.htm",true);

Cela signifie que vous devez faire une requête GET asynchrone pour extraire la page SBL_PROBES.htm . La fonction send (...) est ensuite appelée et déclenche la requête elle-même.

Nous avons enregistré une fonction de rappel pour onreadystatechange, comme vous pouvez l'imaginer, il s'agit en fait d'un gestionnaire d'événements. Chaque fois que l'état change, cette fonction est appelée. (C'est la même chose que si vous enregistrez une fonction de rappel dans un événement onKeyUp dans un formulaire, ce rappel est déclenché à chaque fois que votre clé est relevée :))

Le seul cas qui présente un intérêt pour votre problème est l'état 4. Pour cette raison, la fonction de rappel handleRequest est appelée uniquement dans l'état 4. À ce moment, votre demande a réellement un résultat et un statut. (Statut signifie que votre serveur Web a renvoyé un code de statut 200 = ok, 404 = non trouvé, etc.)

Ce n’est pas toute la magie qui se cache derrière les fichiers ajax, mais qui devrait vous donner un aperçu simplifié de ce qui se passe réellement dans les coulisses. // pour tester.

Si vous avez besoin d'informations plus détaillées, faites le moi savoir.

16
evildead

Status Zero arrive pour deux raisons.

  1. Vous exécutez le protocole de fichier. 
  2. Quelque chose est en train de revenir en arrière de la page lorsque la demande Ajax est active.

Je crois que vous voyez le numéro 2 ici. SO vous devez annuler le clic du bouton.

<button type="button" onclick="loadXMLDoc(); return false;">CHange Content</button>

Dans votre code ci-dessus, cette alerte (T) dira toujours rien lorsque la demande est asynchrone. 

9
epascarello

C'est parce que async retourne avant la requête. Les demandes synchrones sont renvoyées après le retour de la demande.

Essayez de manipuler votre logique ici.

xmlhttp.onreadystatechange=function()
  {
    alert ("rdystate: " + xmlhttp.readyState);
    alert ("status: "   + xmlhttp.status);
    alert ("Text: "     + xmlhttp.statusText);
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
      T = xmlhttp.responseText;
      alert(T);
    }
  }
3
Daniel A. White

J'ai lutté contre le problème de ne pas obtenir de résultat lors de l'utilisation de l'instruction ouverte XMLHttpRequest asynchrone. Puisque cette question est la première que j'ai trouvée en utilisant Google, voici comment je l'ai résolue: 

Si vous utilisez un bouton qui se trouve dans un formulaire, assurez-vous qu'il est défini sur type = "submit" et onclick = "return myFunction ()". Et dans myFunction (), assurez-vous de renvoyer false, not true! En retournant true à partir de la fonction, vous rechargez la page et l'objet XML disparaît. Si vous renvoyez false, la demande XML obtient le temps nécessaire pour terminer et la fonction onreadystatechange sera exécutée.

Source: Flask Mailing List

1
Adalars1

J'ai maintenant reçu la bonne réponse à ce problème commun. La réponse suit:

C'est un problème très courant lors du développement pour le Web. Il y a deux façons de le contourner.

  1. La première consiste à utiliser JSONP, que notre API prend en charge lorsque vous ajoutez un paramètre de requête ("? Callback = foo"). Cela devrait vous permettre de démarrer immédiatement et est excellent pour le développement, mais il n'est pas sécurisé pour une utilisation en production, car les utilisateurs ont accès à votre clé API.
  2. La deuxième (qui correspond à ce que nous utilisons sur Forecast et à la meilleure méthode de production) consiste à configurer un serveur proxy sur votre propre domaine, qui peut envoyer des requêtes à Forecast au nom de l'utilisateur. Cela contourne la politique de même origine du navigateur, empêche les utilisateurs d'accéder à votre clé API (qui peut être stockée côté serveur) et vous permet également d'utiliser la mise en cache des demandes, si vous le souhaitez. (Notre serveur Web préféré, NGINX, prend en charge cette configuration et est très facile à configurer. Si vous avez besoin de quelques exemples de configuration, contactez-nous!)
0
Stan Truffaut