jQuery xml错误'No'Access-Control-Allow-Origin'标头出现在请求的资源上。

时间:2013-11-06 20:07:53

标签: javascript jquery ajax xml-parsing cors

我正在处理我的这个个人项目,只是为了好玩,我想读取位于http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml的xml文件并解析xml并用它来转换货币之间的值。

到目前为止,我已经提出了下面的代码,这对于读取xml非常基本,但是我得到以下错误。

  

XMLHttpRequest无法加载****。没有'Access-Control-Allow-Origin'   标头出现在请求的资源上。起源   因此,“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');
            }
         });
    }
);

我没有看到我的代码有任何问题,所以我希望有人可以指出我的代码错误,以及我如何解决它。

2 个答案:

答案 0 :(得分:163)

由于same-origin policy,您将无法通过http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml部署的文件对http://run.jsbin.com进行ajax调用。


由于源(又名来源)页面和目标网址位于不同的域(run.jsbin.comwww.ecb.europa.eu),您的代码是实际上是在尝试发出 Cross-domain (CORS) 请求,而不是普通的GET

简而言之,同源策略表示浏览器应该只允许对HTML页面的相同域的服务进行ajax调用。


实施例

http://www.example.com/myPage.html的网页只能直接请求位于http://www.example.com的服务,例如http://www.example.com/api/myService。如果服务托管在另一个域(例如http://www.ok.com/api/myService),则浏览器不会直接拨打电话(正如您所期望的那样)。相反,它会尝试发出CORS请求。

简而言之,要在不同的域,您的浏览器上执行(CORS)请求*:

  • 在原始请求中包含Origin标头(页面的域名为值)并照常执行;然后
  • 只有当服务器响应包含允许CORS请求的adequate headers (Access-Control-Allow-Origin is one of them)时,浏览才会完成调用(几乎**完全一样)如果HTML页面位于同一个域,那就好了。
    • 如果没有预期的标题,浏览器就会放弃(就像它对你做的那样)。


*上面描述了简单请求中的步骤,例如没有花哨标题的常规GET。如果请求不简单(例如POST application/json作为内容类型),浏览器会暂停一下,并且在完成请求之前,会先发送OPTIONS个请求目标网址。如上所述,只有在对此OPTIONS请求的响应包含CORS标头时,它才会继续。此OPTIONS来电称为预检请求。
**我说几乎因为常规调用和CORS调用之间存在其他差异。一个重要的问题是,即使响应中存在某些标头,也会not be picked up by the browser if they aren't included in the Access-Control-Expose-Headers标题。


如何解决?

这只是一个错字吗?有时JavaScript代码在目标域中只有一个拼写错误。你检查过吗?如果页面位于www.example.com,则只会定期拨打www.example.com!其他网址(例如api.example.com甚至example.comwww.example.com:8080被浏览器视为不同域名!是的,如果端口不同,则它是一个不同的域!

添加标题。 启用 CORS的最简单方法是将必要的标题(如Access-Control-Allow-Origin)添加到服务器的响应中。 (每种服务器/语言都有办法 - check some solutions here。)

最后的手段:如果您没有服务器的服务器端访问权限,您也可以镜像它(通过反向代理等工具),并包括所有必要的标题都在那里。

答案 1 :(得分:29)

如果您在服务器上启用了php,那么有一种非常好的方法可以做到这一点。改变这一行:

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

到这一行:

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

然后在php脚本中(如果您有权使用file_get_contents()函数):

<?php

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

?>

Php似乎并不介意这个网址来自不同的来源。就像我说的,这是一个hacky的答案,我确信它有问题,但它对我有用。

编辑: 如果你想在php中缓存结果,这里是你要使用的php文件:

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

?>

缓存代码取自here