web-dev-qa-db-fra.com

Erreur xml jQuery 'Aucun en-tête' Access-Control-Allow-Origin 'n'est présent sur la ressource demandée.'

Je travaille sur mon projet personnel juste pour le plaisir, où je veux lire un fichier XML qui se trouve à l'adresse http://www.ecb.europa.eu/stats/eurofxref/eurofxref -daily.xml et analysez le fichier XML et utilisez-le pour convertir les valeurs entre les devises.

Jusqu'ici, j'ai trouvé le code ci-dessous qui est assez basique pour lire le xml mais j'obtiens l'erreur suivante.

XMLHttpRequest ne peut pas charger ****. Aucun en-tête 'Access-Control-Allow-Origin' n'est présent sur la ressource demandée. Origin ' http://run.jsbin.com ' n'est donc pas autorisé à accéder.

$(document).ready( 
    function() {     
        $.ajax({          
            type:  'GET',
            url:   'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml',
            dataType: 'xml',              
            success: function(xml){
                alert('aaa');
            }
         });
    }
);

Je ne vois rien de mal avec mon code, j'espère donc que quelqu'un pourra indiquer ce que je ne fais pas avec mon code et comment je pourrais le corriger.

89
Bazinga777

Vous ne pourrez pas effectuer d’appel ajax vers _http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml_ à partir d’un fichier déployé à _http://run.jsbin.com_ en raison de la règle same-origin policy .


En tant que page source (alias Origin ) et l’URL cible sont à différents domaines (_run.jsbin.com_ et _www.ecb.europa.eu_), votre code tente réellement de créer un interdomaine (CORS) demande, pas un GET ordinaire.

En quelques mots, la politique de même origine indique que les navigateurs ne doivent autoriser que les appels ajax aux services du même domaine de la page HTML.


Exemple:

Une page sur _http://www.example.com/myPage.html_ ne peut demander directement que des services situés à _http://www.example.com_, tels que _http://www.example.com/api/myService_. Si le service est hébergé sur un autre domaine (par exemple, _http://www.ok.com/api/myService_), le navigateur ne passe pas l'appel directement (comme vous le souhaitiez). Au lieu de cela, il essaiera de faire une demande CORS.

En bref, pour effectuer une demande (CORS) * dans différents domaines, votre navigateur:

  • Inclut un en-tête Origin dans la demande d'origine (avec le domaine de la page comme valeur) et l'exécute comme d'habitude; puis
  • Seulement si le serveur répond à cette requête contient les en-têtes adéquats ( _Access-Control-Allow-Origin_ est un d'entre eux ) permettant la demande CORS, le parcours complétera le appelez (presque ** exactement comme si la page HTML se trouvait dans le même domaine).
    • Si les en-têtes attendus ne viennent pas, le navigateur abandonne simplement (comme il vous l'a fait).


* Ce qui précède décrit les étapes d'une requête simple , telle qu'un GET normal, sans en-tête fantaisie. Si la demande n’est pas simple (comme un POST avec _application/json_ comme type de contenu), le navigateur l’enregistre pendant un moment et, avant d’exécuter cette requête, envoie d’abord une demande OPTIONS à l'URL cible. Comme ci-dessus, il ne continuera que si la réponse à cette demande OPTIONS contient les en-têtes CORS. Cet appel OPTIONS est appelé demande preflight .
** Je dis presque car il existe d'autres différences entre les appels normaux et les appels CORS. Un point important est que certains en-têtes, même s'ils sont présents dans la réponse, seront ne seront pas récupérés par le navigateur s'ils ne sont pas inclus dans le Access-Control-Expose-Headers en-tête.


Comment le réparer?

S'agissait-il simplement d'une faute de frappe? Parfois, le code JavaScript n'a qu'une faute de frappe dans le domaine cible. Avez-vous vérifié? Si la page est à _www.example.com_, seuls les appels réguliers à _www.example.com_! D'autres URL, telles que _api.example.com_ ou même _example.com_ ou _www.example.com:8080_ sont considérées comme des domaines différents par le navigateur! Oui, si le port est différent, le domaine est différent!

Ajoutez les en-têtes. Le moyen le plus simple de activer CORS consiste à ajouter les en-têtes nécessaires (comme _Access-Control-Allow-Origin_) aux réponses du serveur. (Chaque serveur/langue a un moyen de le faire - cochez quelques solutions ici .)

Dernier recours: Si vous n’avez pas accès au service côté serveur, vous pouvez également le mettre en miroir (via des outils tels que inverser les mandataires ), et y inclure tous les en-têtes nécessaires.

163
acdcjunior

Il y a une sorte de moyen astucieux de le faire si vous avez activé php sur votre serveur. Changer cette ligne:

url:   'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml',

à cette ligne:

url: '/path/to/phpscript.php',

puis dans le script php (si vous êtes autorisé à utiliser la fonction file_get_contents ()):

<?php

header('Content-type: application/xml');
echo file_get_contents("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");

?>

Php ne semble pas s'inquiéter si cette URL est d'une origine différente. Comme je l'ai dit, il s'agit d'une réponse simpliste, et je suis sûr que quelque chose ne va pas, mais cela fonctionne pour moi.

Edit: Si vous voulez mettre le résultat en cache en php, voici le fichier php que vous utiliseriez:

<?php

$cacheName = 'somefile.xml.cache';
// generate the cache version if it doesn't exist or it's too old!
$ageInSeconds = 3600; // one hour
if(!file_exists($cacheName) || filemtime($cacheName) > time() + $ageInSeconds) {
  $contents = file_get_contents('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');
  file_put_contents($cacheName, $contents);
}

$xml = simplexml_load_file($cacheName);

header('Content-type: application/xml');
echo $xml;

?>

Le code de cache prend entre ici .

29
jyapayne