web-dev-qa-db-fra.com

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

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) de Panoramio, une erreur se produit 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&maxx=0&maxy=15 . L'origine nulle n'est pas autorisée par Access-Control-Allow-Origin.

Si j'interroge directement cette URL depuis un navigateur, cela fonctionne bien. Que se passe-t-il et puis-je contourner ce problème? Est-ce que je compose mal ma requête ou est-ce quelque chose que Panoramio fait pour empêcher ce que j'essaie de faire?

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

EDIT

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 à cet égard. LE CODE CI-DESSUS IS WRONG. Utilisez ceci à 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...
  });
});
528
Drew Noakes

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

  1. Vous ne transmettiez pas de spécificateur de type "jsonp" à votre $.get, il utilisait donc un XMLHttpRequest ordinaire. Cependant, votre navigateur prenait en charge le partage de ressources entre origines (CORS) pour autoriser XMLHttpRequest entre domaines si le serveur le confirmait. C'est là que l'en-tête Access-Control-Allow-Origin est entré.

  2. Je crois que vous avez mentionné que vous l’exécutiez à partir d’un fichier: // URL. Les en-têtes CORS peuvent signaler de deux manières qu'une XHR entre domaines est correcte. L'une consiste à envoyer Access-Control-Allow-Origin: * (ce qui devait être le cas si vous atteigniez Flickr via $.get), tandis que l'autre devait renvoyer le contenu de l'en-tête Origin. Cependant, les URL file:// produisent une valeur null Origin qui ne peut pas être autorisée via écho-back.

La proposition de Darin d'utiliser $.getJSON a résolu le premier problème d'une manière détournée. Cela fait un peu de magie de changer le type de requête de "json" par défaut à "jsonp" s'il voit la sous-chaîne callback=? dans l'URL.

Cela a résolu le problème en n'essayant plus d'exécuter une requête CORS à partir d'une URL file://.

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 $.get et réglez dataType sur jsonp.
    • Vous utilisez $.getJSON et avez inclus callback=? dans l'URL.
  2. Si vous essayez d'effectuer une XMLHttpRequest inter-domaines via CORS ...
    1. Assurez-vous de tester via http://. Les scripts exécutés via file:// ont un support limité pour CORS.
    2. Assurez-vous que le navigateur supporte réellement CORS . (Opera et Internet Explorer sont en retard à la fête)
416
ssokolow

Vous devez peut-être ajouter un HEADER dans votre script appelé, voici ce que je devais faire en PHP:

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

Plus de détails en Domaine croisé AJAX ou services WEB (en français).

74
Thomas Decaux

Pour un projet HTML simple:

cd project
python -m SimpleHTTPServer 8000

Puis parcourez votre fichier.

68
CodeGroover

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);
});

Aussi, je vous recommanderais d'utiliser plutôt la méthode $.getJSON() 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 à partir d'ici .


MISE À JOUR:

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

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

20
Darin Dimitrov

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 en-têtes sophistiqués.

8
Cheng Chen

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.

5
Quentin

Nous l'avons géré via le fichier http.conf (é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.

4
romu31

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

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

4
user2701060

Dans mon cas, le même code fonctionnait bien 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é à ce moment-là.

3
Kalpesh Patel

Tous les serveurs ne supportent pas jsonp. Le serveur doit définir la fonction de rappel dans ses résultats. J'utilise ceci pour obtenir des réponses JSON à partir de sites qui renvoient du JSON pur mais ne supportent pas 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;
    });
}
2
mAsT3RpEE

J'utilise le serveur Apache, donc j'ai 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.

1
zenio

Comme note finale le la documentation de Mozilla dit explicitement que

L'exemple ci-dessus échouerait si l'en-tête avait un caractère générique: Access-Control-Allow-Origin: *. Depuis explicitement le contrôle d'accès-autoriser-l'origine mentions http: //foo.example , le contenu reconnaissant les informations d'identification est renvoyé au contenu Web appelant.

En conséquence, l'utilisation de '*' n'est pas simplement une mauvaise pratique. Tout simplement ne fonctionne pas :)

1
user2688838

Pour PHP - cela fonctionne 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: //

0
Tyler

J'ai également eu la même erreur dans Chrome (je n'ai pas testé d'autres ventilateurs). C'était dû au fait que je naviguais sur domain.com au lieu de www.domain.com. Un peu étrange, mais je pourrais 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 nécessaire.

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

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 l'utilisation de JQuery 1.11.1

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

En cherchant un peu, j'ai trouvé celui-ci Pour utiliser:

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

Et ensuite, il servira à http://localhost:8000.

0
MiJyn

Gens,

J'ai rencontré un problème similaire. Mais en utilisant Fiddler, j'ai pu comprendre le problème. Le problème est que l'URL du client configuré 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 à peu près ceci:

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

C'est vraiment bizarre parce que cela fonctionnait sans aucun problème sur Internet Explorer, mais 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. Désormais, l'API est accessible via Chrome et Internet Explorer sans aucun problème. S'il vous plaît donner à cela un coup de feu.

Merci Andy

0
andymenon