我正在处理我的这个个人项目,只是为了好玩,我想读取位于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');
}
});
}
);
我没有看到我的代码有任何问题,所以我希望有人可以指出我的代码错误,以及我如何解决它。
答案 0 :(得分:163)
由于same-origin policy,您将无法通过http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml
部署的文件对http://run.jsbin.com
进行ajax调用。
由于源(又名来源)页面和目标网址位于不同的域(run.jsbin.com
和www.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
标头(页面的域名为值)并照常执行;然后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.com
或www.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。