XMLHttpRequest status 0 (responseText est vide)

104

Impossible d'obtenir des données avec XMLHttpRequest (le statut 0 et le responseText sont vides):

xmlhttp = new XMLHttpRequest ();
xmlhttp.open ("GET", "http://www.w3schools.com/XML/cd_catalog.xml", true);
xmlhttp.onreadystatechange = fonction () 
{
  si (xmlhttp.readyState == 4)
    alert ("status" + xmlhttp.status);
}
xmlhttp.send ();

Il alerte "état 0".

La même situation avec la requête localhost (cd_catalog.xml est enregistré en tant que fichier local)

xmlhttp.open ("GET", "http: //localhost/cd_catalog.xml", true);

Mais avec la requête IP localhost

xmlhttp.open ("GET", "http://127.0.0.1/cd_catalog.xml", true);

et avec la demande de fichier local

xmlhttp.open ("GET", "cd_catalog.xml", true);

tout va bien (état 200)

Qu'est-ce qui peut causer le problème (statut = 0) avec la demande en ligne?

PS: Live HTTP Headers montre que tout est OK dans les 4 cas:

  HTTP / 1.1 200 OK
  Content-Longueur: 4742

PS2: serveur Web local Apache sur VMWare (OS hôte Win7, OS invité Ubuntu, adaptateur réseau - NAT). Navigateur - Firefox.

Arigasa
la source
1
Votre page de test est-elle http://127.0.0.1par hasard? ;)
Roatin Marth
Oui. <code> 127.0.0.1/CDCatalogTest.html </code>
arigasa
7
Vous avez répondu à votre question. XMLHttpRequestne peut pas faire de requêtes inter-domaines. Il existe cependant quelques solutions de contournement. Regardez jquery, par exemple.
meze
Utilisez php pour obtenir le fichier. Peu de contournement: jquery-howto.blogspot.com/2009/04/…
2
@meze: les appels inter-domaines fonctionnent avec jQuery. Mais comment ne pas fonctionner avec du JavaScript brut, car jQuery est implémenté en JavaScript? Ça n'a aucun sens. JQuery utilise-t-il une sorte de solution de contournement désagréable?
Gruber

Réponses:

55

status est 0 lorsque votre fichier html contenant le script est ouvert dans le navigateur via le schéma de fichiers. Assurez-vous de placer les fichiers sur votre serveur (apache ou tomcat peu importe), puis ouvrez-le via le protocole http dans le navigateur. (ie http: //localhost/myfile.html ) C'est la solution.

Abhishek_8
la source
1
Pourquoi ce vote est-il défavorable? C'est en fait vrai! Les requêtes XHR de file: // URL des fichiers également sur file: // Les URL ont en fait le statut == 0 en cas de succès (testé sur FF 24.0.5).
Daniel Roethlisberger
3
J'obtiens également le statut == 0 en cas de succès sur Safari version 6.1.6.
Planar le
J'ai le statut = 0 (mais le statut 200 sur le réseau) en utilisant Charger le module complémentaire temporaire sur Firefox
JobaDiniz
1
réponse toujours valable. La réponse HTTP est de 200 pour les schémas distants réels (http et al.) Et 0 pour le fichier local ( file://schéma). De toute évidence, vous devez d'abord autoriser le chargement de fichiers locaux en désactivant CORS.
pid
31

La cause de vos problèmes est que vous essayez de faire un appel inter-domaines et cela échoue .

Si vous faites du développement localhost, vous pouvez passer des appels inter-domaines - je le fais tout le temps.

Pour Firefox, vous devez l'activer dans vos paramètres de configuration

signed.applets.codebase_principal_support = true

Ajoutez ensuite quelque chose comme ceci à votre code ouvert XHR:

  if (isLocalHost()){
    if (typeof(netscape) != 'undefined' && typeof(netscape.security) != 'undefined'){
      netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');
    }
  }

Pour IE, si je me souviens bien, tout ce que vous avez à faire est d'activer le paramètre de sécurité du navigateur sous «Divers → Accéder aux sources de données à travers les domaines» pour le faire fonctionner avec ActiveX XHR.

IE8 et les versions ultérieures ont également ajouté des capacités inter-domaines aux objets XmlHttpRequest natifs, mais je n'ai pas encore joué avec ceux-ci.

Prison
la source
8
Au cas où quelqu'un en aurait besoin, pour Chrome, vous devez en lancer une nouvelle instance (sans aucune déjà ouverte) et utiliser--allow-file-access-from-files
TheZ
@TheZ: Êtes-vous à 100%? J'ai entendu dire que vous n'avez qu'à exécuter une nouvelle instance de Chrome, avec un --allow-file-access-from-filescommutateur, mais que vous n'avez pas à fermer toutes les autres instances en cours d'exécution. Exactement comme dans le cas du mode de navigation privée de Chrome - vous pouvez l'utiliser sans fermer aucune autre instance en cours d'exécution.
trejder
Il semble que la prise en charge de «UniversalBrowserRead» a été abandonnée, donc cette solution n'est pas une option.
perilandmishap
En outre, cela peut arriver lorsque vous demandez une page http à partir de la page https (comme une extension dans le navigateur).
sibvic
Je rencontre ce problème, malgré la page html et le script AJAX résidant dans le même domaine. Mais bizarrement, cela n'affecte que certains scripts, notamment tous les scripts qui accèdent aux ressources MongoDB. Des indices sur pourquoi c'est?
David Edwards
26

Assurez-vous en fait que votre type de bouton est Button not Submit, ce qui a provoqué un conflit de statut là où je me suis rencontré récemment.

Dyuan
la source
1
Il y a un conflit car l'envoi d'un formulaire a un comportement par défaut que vous devez éviter si vous gérez l'événement et effectuez un appel ajax vous-même. Vous pouvez empêcher le comportement par défaut en prenant l'événement dans votre gestionnaire et en appelante.preventDefault()
Jordan
20

Si le serveur répond à une méthode OPTIONS et à GET et POST (selon celui que vous utilisez) avec un en-tête comme:

Access-Control-Allow-Origin: *

Cela pourrait fonctionner correctement. Semble dans FireFox 3.5 et rekonq 0.4.0. Apparemment, avec cet en-tête et la réponse initiale à OPTIONS, le serveur dit au navigateur: "Allez-y et laissez passer cette requête interdomaine."

Alex Robinson
la source
3
C'est la bonne réponse! Regardez en.wikipedia.org/wiki/Cross-origin_resource_sharing pour plus d'informations. Si vous ajoutez cet en-tête, ce n'est pas «pourrait fonctionner», mais «fonctionnera». NB Ce que vous devez ajouter est un HTTP / réponse / en-tête - vous ne pouvez donc le faire que sur un serveur que vous contrôlez. Il ne sera jamais possible de récupérer directement w3schools.com/XML/cd_catalog.xml en utilisant XMLHttpRequest(c'est-à-dire selon la question d'origine), car cette ressource n'inclut pas (au moins, à partir du 24 avril 2015) un tel en-tête CORS.
MikeBeaton
13

Considérez également le délai d'expiration de la demande :

Le navigateur moderne renvoie readyState = 4 et s tatus = 0 si trop de temps s'écoule avant la réponse du serveur.

Andrea Savojardo
la source
3
@AndreaSavojardo: Avez-vous des références (comme un article sur MDN) sur la conformité de ce comportement aux normes?
Alexander Abakumov
@AndreaSavojardo J'ai readyState = 4 et status = 0 et le serveur n'est pas en cours d'exécution mais l'alerte d'erreur est affichée rapidement .... combien de temps passe pour "time out de la demande"?
7

Ajoutez setRequestHeader("Access-Control-Allow-Origin","*")à la réponse de votre serveur.

Ivan
la source
3

J'avais fait face à un problème similaire. Tout allait bien, le "readystate" était de 4, mais le "status" était de 0. C'était parce que j'utilisais un serveur portable Apache PHP et que mon fichier dans lequel j'utilisais l'objet "XMLHttpRequest" était un fichier html. J'ai changé l'extension de fichier en php et le problème a été résolu.

Reyan
la source
3

Ouvrez la console javascript . Vous y verrez un message d'erreur. Dans mon cas, c'était CORS.

Jarekczek
la source
2

Pour répondre à la question de savoir pourquoi http://127.0.0.1/cd_catalog.xmlfonctionne mais http://localhost/cd_catalog.xmlpas: Firefox traite 127.0.0.1 et localhost comme deux domaines différents.

Tomi Aarnio
la source
2

Pour voir quel est le problème, lorsque vous obtenez l'erreur cryptique 0, accédez à ... | Plus d'outils | Outils de développement (Ctrl + Maj + I) dans Chrome (sur la page donnant l'erreur)

Lisez le texte rouge dans le journal pour obtenir le vrai message d'erreur. S'il y en a trop, cliquez avec le bouton droit de la souris et effacez la console, puis faites à nouveau votre dernière requête.

Mon premier problème était que je transmettais pour la première fois les en-têtes d'autorisation à mon propre service Web inter-domaines pour le navigateur.

J'ai déjà eu:

Access-Control-Allow-Origin: *

Mais non:

Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization

dans l'en-tête de réponse de mon service Web.

Après avoir ajouté cela, mon erreur zéro a disparu de mon propre serveur Web, ainsi que lors de l'exécution du fichier index.html localement sans serveur Web, mais donnait toujours des erreurs dans le stylet de code.

Retour à ... | Plus d'outils | Developer Tools tout en obtenant l'erreur dans codepen, et il est clairement expliqué: codepen utilise https, donc je ne peux pas faire d'appels vers http, car la sécurité est inférieure.

J'ai donc besoin d'héberger mon service web sur https.

Savoir comment obtenir le vrai message d'erreur - inestimable!

Maya
la source
J'ai utilisé cette approche (f12 dans chrome) et j'ai découvert que j'essayais de passer de https à http qui échouait silencieusement sans rien fournir d'utile. MESSAGE D'ERREUR: VM1152: 1 Contenu mixte: la page à a 'https://mysiteoriginsite' été chargée via HTTPS, mais a demandé un point de terminaison XMLHttpRequest non sécurisé 'http://MyDestinationSite/MyService.svc'. Cette demande a été bloquée; le contenu doit être diffusé via HTTPS.
GrayDwarf
1

Voici un autre cas dans lequel status === 0 , spécifique au téléchargement:

Si vous attachez un 'load'gestionnaire d'événements à XHR.upload, comme suggéré par MDN ( faites défiler vers le bas jusqu'à la partie téléchargement de «Surveillance de la progression»), l'objet XHR aura status=0et toutes les autres propriétés seront des chaînes vides. Si vous attachez le'load' gestionnaire directement à l'objet XHR, comme vous le feriez lors du téléchargement de contenu, tout devrait bien se passer (étant donné que vous n'utilisez pas localhost).

Cependant, si vous souhaitez obtenir de bonnes données dans vos 'progress'gestionnaires d'événements, vous devez attacher un gestionnaire à XHR.upload, pas directement à l'objet XHR lui-même.

Je n'ai testé cela jusqu'à présent que sur Chrome OSX, donc je ne sais pas à quel point le problème ici est la documentation de MDN et à quel point la mise en œuvre de Chrome ...

ericsoco
la source
1

Alex Robinson donne déjà (et d'abord) la bonne réponse à ce problème. Mais pour l'élaborer un peu plus ...

Vous devez ajouter l'en-tête de réponse HTTP:

Access-Control-Allow-Origin: *

Si vous faites cela, le résultat n'est pas simplement «pourrait fonctionner», mais «fonctionnera».

NB Ce que vous devez ajouter est un en- tête de réponse HTTP - vous ne pouvez donc le faire que sur un serveur que vous contrôlez. Il ne sera jamais possible d'extraire directement http://w3schools.com/XML/cd_catalog.xml à partir de son URL d'origine en utilisant un XMLHttpRequest(selon la question de l'OP), car cette ressource ne le fait pas (du moins, pas à partir du 24 avril 2015) inclure un tel en-tête CORS.

http://en.wikipedia.org/wiki/Cross-origin_resource_sharing donne plus d'informations.

MikeBeaton
la source
0

Mon problème similaire à celui-ci a été résolu en vérifiant mon code html. J'avais un onclickgestionnaire dans mon bouton de soumission de formulaire à une méthode. comme ceci: onclick="sendFalconRequestWithHeaders()". Cette méthode appelle à son tour ajax comme la vôtre et fait ce que je veux. Mais pas comme prévu, mon navigateur ne retournait rien.

Appris du travail acharné de quelqu'un , je suis retourné faux dans ce gestionnaire et résolu. Permettez - moi de mentionner que , avant d' arriver à ce poste, j'ai passé un week - end de 3 jours et une demi - journée dans le code d'écriture de bureau d' exécution CORS filters, jetty configautres jersey and embedded jettychoses connexes - juste pour résoudre ce problème, tournant autour de mon entendement.cross domain ajax requests Et d'autres choses normes. C'était ridicule de voir à quel point de simples erreurs de JavaScript vous rendaient stupide.

Pour être vrai, j'ai essayé signed.applets.codebase_principal_support = trueet écrit isLocalHost() **if**. peut-être que cette méthode doit être implémentée par nous, Firefox dit qu'il n'y en a pas. Maintenant, je dois nettoyer mon code pour soumettre le correctif git proprement. Merci à ce quelqu'un.

Siva Tumma
la source
0

Une requête de navigateur "127.0.0.1/somefile.html" arrive inchangée sur le serveur Web local, tandis que "localhost / somefile.html" peut arriver sous la forme "0: 0: 0: 0: 0: 0: 0: 1 / somefile.html "si IPv6 est pris en charge. Ainsi, ce dernier peut être traité comme allant d'un domaine à un autre.

Massimo Roscio
la source
0

Alex Robinson et bmju ont fourni des informations précieuses pour comprendre les problèmes d'origine croisée. Je voulais ajouter que vous devrez peut-être faire un appel OPTIONS explicite dans votre code client avant d'effectuer le GET / POST souhaité (par exemple, contre un point de terminaison de service CORS OAuth). Votre navigateur / bibliothèque peut ne pas traiter automatiquement la demande OPTIONS. Gruber, c'est l'une des réponses possibles à votre question.

Tim McConnell
la source
0

J'ai eu le même problème (readyState était 4 et status 0) , puis j'ai suivi une approche différente expliquée dans ce tutoriel: https://spring.io/guides/gs/consuming-rest-jquery/

Il n'a pas du tout utilisé XMLHttpRequest , à la place il a utilisé la méthode jquery $ .ajax () :

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="hello.js"></script>
</head>

<body>
    <div>
        <p class="greeting-id">The ID is </p>
        <p class="greeting-content">The content is </p>
    </div>
</body>

et pour le fichier public / hello.js (ou vous pouvez l'insérer directement dans le même code HTML):

$(document).ready(function() 
 {
    $.ajax({
        url: "http://rest-service.guides.spring.io/greeting"
   }).then(function(data) {
      $('.greeting-id').append(data.id);
      $('.greeting-content').append(data.content);
   });
 });
RMDev
la source
2
Vous réalisez que jQuery $.ajax()utilise XMLHttpRequestà l'intérieur, n'est-ce pas?
Manngo le
-1

Je viens d'avoir ce problème parce que je l'ai utilisé 0.0.0.0comme serveur, je l' ai changé localhostet cela fonctionne.

Vad
la source
-4

Edit: Veuillez lire les commentaires de Malvolio ci-dessous car la connaissance de cette réponse est obsolète.

Vous ne pouvez pas effectuer de requêtes XMLHttpRequests inter-domaines.

L'appel à 127.0.0.1fonctionne parce que votre page de test est située à 127.0.0.1, et le test local fonctionne également puisque, eh bien ... c'est un test local.

Les deux autres tests échouent car JavaScript ne peut pas communiquer avec un serveur distant via XMLHttpRequest.

Vous pouvez plutôt envisager:

  • XMLHttp-demandez à votre propre serveur de récupérer votre contenu XML distant pour vous (script php, par exemple)
  • Essayer d'utiliser un service comme GoogleAppEngine si vous souhaitez le conserver en JavaScript complet.

J'espère que cela pourra aider

Gabriel Sprenger
la source
40
C'est tout simplement faux. Vous pouvez effectuer des requêtes XMLHttpRequests inter-domaines.
Malvolio
1
"Vous ne pouvez pas" comme "Vous ne devriez pas le faire parce que ce n'est jamais une bonne idée"
Gabriel Sprenger
24
- assez juste, mais je ne sais pas si un commentaire est le meilleur forum pour cela. Les requêtes XMLHttpRequests inter-domaines ont certes des problèmes de sécurité, mais elles offrent tous les outils nécessaires pour faire face à ces défis. Cela mis à part, ils permettent aux sites Web d'offrir facilement des services à d'autres sites Web, d'utiliser les CDN pour propager des données et de répondre plus rapidement aux demandes des utilisateurs. Si vous avez des questions spécifiques, vous pouvez m'envoyer un message, ou mieux, poster une question ici sur SO et attirer mon attention dessus.
Malvolio
2
@GabrielSprenger: Le cross-domain XMLHttpRequestn'est pas seulement une bonne idée, c'est tellement courant de nos jours que NE PAS les faire dans une application Web moderne (au-delà d'une sorte de HelloWorlds) est quelque chose de ridicule. Tout service REST externe consommé par votre application nécessite un inter-domaine XMLHttpRequest. Et c'est pourquoi tout ce truc CORS a été ajouté.
Alexander Abakumov