Erreur XmlHttpRequest: l'origine null n'est pas autorisée par Access-Control-Allow-Origin

550

Je développe une page qui extrait des images de Flickr et Panoramio via le support AJAX de jQuery.

Le côté Flickr fonctionne bien, mais lorsque j'essaie de $.get(url, callback)partir de Panoramio, je vois une erreur dans la console de Chrome:

XMLHttpRequest ne peut pas charger http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=processImages&minx=-30&miny=0&maxx=0&maxy=150 . L'origine nulle n'est pas autorisée par Access-Control-Allow-Origin.

Si je demande directement cette URL à partir d'un navigateur, cela fonctionne très bien. Que se passe-t-il et puis-je contourner cela? Suis-je en train de composer ma requête de manière incorrecte, ou est-ce quelque chose que Panoramio fait pour entraver ce que j'essaie de faire?

Google n'a trouvé aucune correspondance utile sur le message d'erreur .

ÉDITER

Voici un exemple de code qui montre le problème:

$().ready(function () {
  var url = 'http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=processImages&minx=-30&miny=0&maxx=0&maxy=150';

  $.get(url, function (jsonp) {
    var processImages = function (data) {
      alert('ok');
    };

    eval(jsonp);
  });
});

Vous pouvez exécuter l'exemple en ligne .

EDIT 2

Merci à Darin pour son aide. LE CODE CI-DESSUS EST MAUVAIS. Utilisez-le à la place:

$().ready(function () {
  var url = 'http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&minx=-30&miny=0&maxx=0&maxy=150&callback=?';

  $.get(url, function (data) {
    // can use 'data' in here...
  });
});
Drew Noakes
la source
1
Qu'est - ce que l'apparence URL comme vous faites la demande à partir ? Cela ne se produit pas à un généré dynamiquement iframeque vous document.writeen, par exemple?
Pekka
5
Pouvez-vous publier la réponse HTTP de la demande à chaque service. Je parie que Panoramio ne diffuse pas Access-Control-Allow-Origin. Voir w3.org/TR/cors pour des exemples.
Kevin Hakanson
2
@Kevin, vous n'avez pas besoin de ces en-têtes si le serveur envoie JSONP.
Darin Dimitrov
@Pekka, j'exécute la page depuis ma machine locale pour le moment ( file:///C:/). Non iframeest impliqué.
Drew Noakes
1
@drew que se passe-t-il si vous l'exécutez à partir d'une URL http? Cela ne devrait pas faire de différence dans ce sens, mais simplement pour exclure la possibilité.
Pekka

Réponses:

423

Pour mémoire, pour autant que je sache, vous avez eu deux problèmes:

  1. Vous ne passiez pas de spécificateur de type "jsonp" à votre $.get, donc il utilisait un XMLHttpRequest ordinaire. Cependant, votre navigateur a pris en charge CORS (Cross-Origin Resource Sharing) pour autoriser XMLHttpRequest entre domaines si le serveur l'a validé. C'est là que l'en- Access-Control-Allow-Origintête est entré.

  2. Je crois que vous avez mentionné que vous l'exécutiez à partir d'un fichier: // URL. Il existe deux façons pour les en-têtes CORS de signaler qu'un XHR interdomaine est OK. L'une consiste à envoyer Access-Control-Allow-Origin: *(ce qui, si vous atteigniez Flickr via $.get, ils devaient le faire) tandis que l'autre était de renvoyer le contenu de l'en- Origintête. Cependant, les file://URL produisent un null Originqui ne peut pas être autorisé via écho-back.

Le premier a été résolu de manière détournée par la suggestion d'utilisation de Darin $.getJSON. Il fait un peu de magie pour changer le type de requête de sa valeur par défaut "json" à "jsonp" s'il voit la sous-chaîne callback=?dans l'URL.

Cela a résolu le second en n'essayant plus d'effectuer une demande CORS à partir d'une file://URL.

Pour clarifier pour d'autres personnes, voici les instructions de dépannage simples:

  1. Si vous essayez d'utiliser JSONP, assurez-vous que l'un des cas suivants est le cas:
    • Vous utilisez $.getet mis dataTypeà jsonp.
    • Vous utilisez $.getJSONet inclus callback=?dans l'URL.
  2. Si vous essayez de faire un XMLHttpRequest inter-domaines via CORS ...
    1. Assurez-vous de tester via http://. Les scripts exécutés via file://ont une prise en charge limitée de CORS.
    2. Assurez-vous que le navigateur prend réellement en charge CORS . (Opera et Internet Explorer sont en retard à la fête)
ssokolow
la source
45
Alors, quelle est la solution à cela?
jQuerybeast
19
rappel =? FTW
Tim
10
Certains navigateurs comme chrome autorisent CORS s'ils sont démarrés avec le paramètre --allow-file-access-from-files
echox
1
callback=?n'a pas fonctionné pour moi, mais jsonp=?a fonctionné. Une explication à cela?
crunkchitis
1
Dois-je installer un serveur Web pour tester via http://? Ou existe-t-il un moyen d'ouvrir simplement le fichier en utilisant ce protocole?
Will Sewell
76

Vous devez peut-être ajouter un HEADER dans votre script appelé, voici ce que j'avais à faire en PHP:

header('Access-Control-Allow-Origin: *');

Plus de détails dans Cross domain AJAX ou services WEB .

Thomas Decaux
la source
1
@Uri: dépend de votre serveur HTTP. Avec Apache, vous voudrez examiner les mod_headers.
ssokolow
4
@Uri <meta http-equiv = "Access-Control-Allow-Origin" content = "*">
Herberth Amaral
7
@HerberthAmaral J'ai essayé d'ajouter ceci à l'intérieur de <head> </head>, mais cela ne fonctionne pas pour moi. Je l'essaye dans iOS Safari et Chrome, mais dans la console, j'obtiens l'origine null n'est pas autorisé par l'erreur Access-Control-Allow-Origin.
thandasoru
3
Cela ne fonctionne pas dans l'en-tête du fichier html pour des raisons de sécurité. Ce doit être un en-tête. stackoverflow.com/questions/7015782/…
Justin Blank
Il ne peut pas être dans le HTML. Il doit être spécifié par le programme qui envoie la page HTML à votre navigateur via le réseau (appelé serveur Web).
Roman Plášil
70

Pour un projet HTML simple:

cd project
python -m SimpleHTTPServer 8000

Parcourez ensuite votre fichier.

CodeGroover
la source
1
bien que génial et fonctionne, lorsque vous allez à 0.0.0.0:8000 et essayez les POSTdemandes que vous obtenez: code 501, message Unsupported method ('POST')pour les googles.
pjammer
"Lorsqu'un serveur Web Python (comme cherrypy par exemple) dit qu'il sert sur 0.0.0.0, cela signifie qu'il écoute tout le trafic TCP qui aboutit sur cette machine, quel que soit le nom d'hôte ou l'adresse IP demandée." Alors peut-être essayez de publier sur localhost: 8000 stackoverflow.com/a/4341808/102022
eric.christensen
20

Fonctionne pour moi sur Google Chrome v5.0.375.127 (je reçois l'alerte):

$.get('http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=?&minx=-30&miny=0&maxx=0&maxy=150',
function(json) {
    alert(json.photos[1].photoUrl);
});

Je vous recommande également d'utiliser la $.getJSON()méthode à la place car la précédente ne fonctionne pas sur IE8 (au moins sur ma machine):

$.getJSON('http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=?&minx=-30&miny=0&maxx=0&maxy=150', 
function(json) {
    alert(json.photos[1].photoUrl);
});

Vous pouvez l'essayer en ligne d'ici .


MISE À JOUR:

Maintenant que vous avez montré votre code, je peux voir le problème. Vous disposez à la fois d'une fonction anonyme et d'une fonction en ligne, mais les deux seront appelés processImages. Voilà comment fonctionne le support JSONP de jQuery. Remarquez comment je définis le callback=?afin que vous puissiez utiliser une fonction anonyme. Vous pouvez en savoir plus à ce sujet dans la documentation .

Une autre remarque est que vous ne devez pas appeler eval. Le paramètre transmis à votre fonction anonyme sera déjà analysé en JSON par jQuery.

Darin Dimitrov
la source
Hmm ok laissez-moi réessayer. Je suis sur une version différente de Chrome btw "6.0.472.51 beta".
Drew Noakes
Votre code a fonctionné pour moi. J'ai mis à jour ma question avec du code qui résout le problème.
Drew Noakes
Merci pour le conseil concernant getJSON ... J'ai bifurqué votre exemple jsFiddle pour montrer le problème ( jsfiddle.net/ZfvKm ) et maintenant voir le message d'erreur XMLHttpRequest ne peut pas charger panoramio.com/wapi/data/… . Origin fiddle.jshell.net n'est pas autorisé par Access-Control-Allow-Origin.
Drew Noakes
@Darin, merci pour la mise à jour. Je vois votre point, et j'ai joué avec quelques combinaisons de cela, mais je n'ai pas encore trouvé un moyen d'accéder à l'objet retourné. Pourriez-vous mettre à jour votre exemple jsFiddle pour montrer l'accès aux données? Si vous définissez le rappel sur, ?le JSON renvoyé est entouré de parenthèses. Vous ne définissez pas de paramètre pour votre fonction de rappel, et la valeur de thisne semble pas avoir d'objet de réponse (au moins, la .datavaleur est null).
Drew Noakes
@Darin, fantastique. Merci beaucoup. Fonctionne bien maintenant. Pour toute autre personne lisant ceci, l'inclusion de callback=?indique à jQuery de générer un nom de fonction aléatoire en interne, ce qui entraîne un appel à la fonction anonyme vers laquelle vous passez .getJSON. J'ai apprécié.
Drew Noakes du
8

Tant que le serveur demandé prend en charge le format de données JSON, utilisez l'interface JSONP (JSON Padding). Il vous permet de faire des demandes de domaine externes sans serveurs proxy ni trucs d'en-tête fantaisistes.

Cheng Chen
la source
5

C'est la même politique d'origine , vous devez utiliser une interface JSON-P ou un proxy s'exécutant sur le même hôte.

Quentin
la source
4

Nous l'avons géré via le http.conffichier (édité puis redémarré le service HTTP):

<Directory "/home/the directory_where_your_serverside_pages_is">
    Header set Access-Control-Allow-Origin "*"
    AllowOverride all
    Order allow,deny
    Allow from all
</Directory>

Dans le Header set Access-Control-Allow-Origin "*", vous pouvez mettre une URL précise.

romu31
la source
1
cela ne fonctionne pas sur Apache de XAMPP. le problème existe toujours.
Raptor
1
C'est dangereux. Voyez ici pourquoi; stackoverflow.com/questions/7564832/…
Rob
C'est dangereux comme l'a dit @RobQuist.
d337
4

Si vous effectuez des tests locaux ou appelez le fichier à partir de quelque chose comme cela, file://vous devez désactiver la sécurité du navigateur.

Sur MAC: open -a Google\ Chrome --args --disable-web-security

user2701060
la source
3

Dans mon cas, le même code a bien fonctionné sur Firefox, mais pas sur Google Chrome. La console JavaScript de Google Chrome a déclaré:

XMLHttpRequest cannot load http://www.xyz.com/getZipInfo.php?zip=11234. 
Origin http://xyz.com is not allowed by Access-Control-Allow-Origin.
Refused to get unsafe header "X-JSON"

J'ai dû supprimer la partie www de l'URL Ajax pour qu'elle corresponde correctement à l'URL d'origine et cela a bien fonctionné ensuite.

Kalpesh Patel
la source
2

Tous les serveurs ne prennent pas en charge jsonp. Il nécessite que le serveur définisse la fonction de rappel dans ses résultats. J'utilise ceci pour obtenir des réponses json de sites qui renvoient du json pur mais ne prennent pas en charge jsonp:

function AjaxFeed(){

    return $.ajax({
        url:            'http://somesite.com/somejsonfile.php',
        data:           {something: true},
        dataType:       'jsonp',

        /* Very important */
        contentType:    'application/json',
    });
}

function GetData() {
    AjaxFeed()

    /* Everything worked okay. Hooray */
    .done(function(data){
        return data;
    })

    /* Okay jQuery is stupid manually fix things */
    .fail(function(jqXHR) {

        /* Build HTML and update */
        var data = jQuery.parseJSON(jqXHR.responseText);

        return data;
    });
}
mAsT3RpEE
la source
1

J'utilise le serveur Apache, j'ai donc utilisé le module mod_proxy. Activer les modules:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Puis ajouter:

ProxyPass /your-proxy-url/ http://service-url:serviceport/

Enfin, passez proxy-url à votre script.

Zenio
la source
1

Comme note finale, la documentation de Mozilla dit explicitement que

L'exemple ci-dessus échouerait si l'en-tête était joker comme: Access-Control-Allow-Origin: *. Dans la mesure où Access-Control-Allow-Origin mentionne explicitement http: //foo.example , le contenu reconnaissant les informations d'identification est renvoyé au contenu Web appelant.

En conséquence, ce n'est pas simplement une mauvaise pratique d'utiliser '*'. Ne fonctionne tout simplement pas :)

user2688838
la source
1

Pour PHP - ce travail pour moi sur Chrome, Safari et Firefox

https://w3c.github.io/webappsec-cors-for-developers/#avoid-returning-access-control-allow-origin-null

header('Access-Control-Allow-Origin: null');

en utilisant axios call php live services avec file: //

Tyler
la source
Cela fonctionne également à partir de moi, notez comment null est une chaîne et non une valeur NULL réelle. Je l'utilise car header('Access-Control-Allow-Origin: '.( trim($_SERVER['HTTP_REFERER'],'/') ?:'null'),true);cela permet également l'origine croisée d'un serveur distant à un autre et tombe à (chaîne) null pour le fichier local.
Louis Loudog Trottier
0

J'ai également eu la même erreur dans Chrome (je n'ai pas testé d'autres browers). C'était dû au fait que je naviguais sur domain.com au lieu de www.domain.com. Un peu étrange, mais j'ai pu résoudre le problème en ajoutant les lignes suivantes à .htaccess. Il redirige domain.com vers www.domain.com et le problème a été résolu. Je suis un visiteur Web paresseux, donc je ne tape presque jamais le www mais apparemment, dans certains cas, il est requis.

RewriteEngine on
RewriteCond %{HTTP_HOST} ^domain\.com$ [NC]
RewriteRule ^(.*)$ http://www.domain.com/$1 [R=301,L]
mslembro
la source
0

Assurez-vous que vous utilisez la dernière version de JQuery. Nous étions confrontés à cette erreur pour JQuery 1.10.2 et l'erreur a été résolue après avoir utilisé JQuery 1.11.1

Ganesh Kamath - «Code Frenzy»
la source
0

Gens,

J'ai rencontré un problème similaire. Mais en utilisant Fiddler, j'ai pu résoudre le problème. Le problème est que l'URL du client configurée dans l'implémentation CORS du côté de l'API Web ne doit pas avoir de barre oblique de fin. Après avoir soumis votre demande via Google Chrome et inspecté l' onglet TextView de la section En- têtes de Fiddler, le message d'erreur indique quelque chose comme ceci:

* "L'origine de la politique spécifiée your_client_url: / 'n'est pas valide. Elle ne peut pas se terminer par une barre oblique."

C'est vraiment original, car cela a fonctionné sans aucun problème sur Internet Explorer, mais cela m'a donné mal à la tête lors des tests avec Google Chrome.

J'ai supprimé la barre oblique dans le code CORS et recompilé l'API Web, et maintenant l'API est accessible via Chrome et Internet Explorer sans aucun problème. Veuillez essayer.

Merci, Andy

andymenon
la source
0

Il y a un petit problème dans la solution publiée par CodeGroover ci - dessus , où si vous changez un fichier, vous devrez redémarrer le serveur pour utiliser réellement le fichier mis à jour (au moins, dans mon cas).

Donc en cherchant un peu, j'ai trouvé celui-ci A utiliser:

sudo npm -g install simple-http-server # to install
nserver # to use

Et puis il servira à http://localhost:8000.

MiJyn
la source
1
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien de référence. Les réponses de lien uniquement peuvent devenir invalides si la page liée change. - De l'avis
Vi100
Clarifié le lien.
MiJyn