Error de jQuery XML "No hay ningún encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado".

Resuelto Bazinga777 asked hace 11 años • 2 respuestas

Estoy trabajando en este proyecto personal mío sólo por diversión, donde quiero leer un archivo xml que se encuentra en http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml y analizar el xml y Úselo para convertir valores entre las monedas.

Hasta ahora he creado el siguiente código, que es bastante básico para leer el XML, pero aparece el siguiente error.

XMLHttpRequest no puede cargar ****. No hay ningún encabezado 'Access-Control-Allow-Origin' en el recurso solicitado. Por lo tanto, no se permite el acceso al origen 'http://run.jsbin.com'.

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

No veo nada malo en mi código, así que espero que alguien pueda señalar qué estoy haciendo mal con mi código y cómo podría solucionarlo.

Bazinga777 avatar Nov 07 '13 03:11 Bazinga777
Aceptado

No podrá realizar una llamada ajax http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xmldesde un archivo implementado http://run.jsbin.comdebido a la política del mismo origen .


Como la página de origen (también conocida como origen ) y la URL de destino están en dominios diferentes ( run.jsbin.comy www.ecb.europa.eu), su código en realidad está intentando realizar una solicitud entre dominios (CORS) , no una solicitud ordinaria GET.

En pocas palabras, la política del mismo origen dice que los navegadores sólo deben permitir llamadas ajax a servicios en el mismo dominio de la página HTML.


Ejemplo:

Una página en http://www.example.com/myPage.htmlsolo puede solicitar directamente servicios que se encuentren en http://www.example.com, como http://www.example.com/api/myService. Si el servicio está alojado en otro dominio (por ejemplo http://www.ok.com/api/myService), el navegador no realizará la llamada directamente (como era de esperar). En cambio, intentará realizar una solicitud CORS.

En pocas palabras, para realizar una solicitud (CORS)* en diferentes dominios, su navegador:

  • Incluirá un Originencabezado en la solicitud original (con el dominio de la página como valor) y lo realizará como de costumbre; y luego
  • Solo si la respuesta del servidor a esa solicitud contiene los encabezados adecuados ( Access-Control-Allow-Origines uno de ellos ) que permiten la solicitud CORS, la navegación completará la llamada (casi** exactamente como lo haría si la página HTML estuviera en el mismo dominio).
    • Si los encabezados esperados no aparecen, el navegador simplemente se da por vencido (como le ocurrió a usted).


* Lo anterior muestra los pasos de una solicitud simple , como una normal GETsin encabezados sofisticados. Si la solicitud no es simple (como un tipo de contenido POSTcon application/jsonas), el navegador la retendrá por un momento y, antes de cumplirla, primero enviará una OPTIONSsolicitud a la URL de destino. Como arriba, solo continuará si la respuesta a esta OPTIONSsolicitud contiene los encabezados CORS. Esta OPTIONSllamada se conoce como solicitud de verificación previa .
** Digo casi porque existen otras diferencias entre las llamadas regulares y las llamadas CORS. Una importante es que algunos encabezados, incluso si están presentes en la respuesta, no serán detectados por el navegador si no están incluidos en elAccess-Control-Expose-Headers encabezado.


¿Como arreglarlo?

¿Fue solo un error tipográfico? A veces, el código JavaScript solo tiene un error tipográfico en el dominio de destino. ¿Te fijaste? Si la página está en www.example.comsólo hará llamadas regulares a www.example.com! ¡Otras URL, como api.example.como incluso example.como, www.example.com:8080son consideradas dominios diferentes por el navegador! Sí, si el puerto es diferente, ¡entonces es un dominio diferente!

Agrega los encabezados. La forma más sencilla de habilitar CORS es agregando los encabezados necesarios (como Access-Control-Allow-Origin) a las respuestas del servidor. (Cada servidor/idioma tiene una forma de hacerlo; consulte algunas soluciones aquí ).

Último recurso: si no tiene acceso al servicio desde el lado del servidor, también puede duplicarlo (a través de herramientas como servidores proxy inversos ) e incluir todos los encabezados necesarios allí.

acdcjunior avatar Nov 06 '2013 20:11 acdcjunior

Hay una forma fantástica de hacerlo si tienes php habilitado en tu servidor. Cambie esta línea:

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

a esta línea:

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

y luego en el script php (si tiene permiso para usar la función file_get_contents()):

<?php

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

?>

A Php no parece importarle si esa URL es de un origen diferente. Como dije, esta es una respuesta engañosa y estoy seguro de que tiene algún problema, pero funciona para mí.

Editar: si desea almacenar en caché el resultado en php, aquí está el archivo php que usaría:

<?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;

?>

El código de almacenamiento en caché se toma de aquí .

jyapayne avatar Dec 17 '2013 22:12 jyapayne