jQuery xml错误'没有'Access-Control-Allow-Origin'标题出现在请求的资源上。
我正在从事这个个人项目,只是为了好玩,我想读一个位于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'); } }); } );
我没有看到我的代码有什么问题,所以我希望有人能指出我在做什么错了我的代码以及如何修复它。
您将无法通过http://run.jsbin.com
部署的文件向http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml
进行ajax调用,因为同源政策 。
由于源(aka origin )页面和目标 URL位于不同的域( run.jsbin.com
和www.ecb.europa.eu
),因此您的代码实际上正尝试创建一个跨域(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
就是其中的一个 ),允许CORS请求时,浏览器才能完成调用(几乎**就像HTML页面那样在同一个域)。- 如果预期的标题不来,浏览器只是放弃(就像你做的那样)。
上面描述了一个简单的请求中的步骤,比如一个没有花哨头的常规GET
。 如果请求不是简单的(比如application/json
作为内容类型的POST
),浏览器会暂停一会儿,在完成之前,会首先向目标URL发送OPTIONS
请求。 像上面一样,只有当对这个OPTIONS
请求的响应包含CORS头时,它才会继续。 这个OPTIONS
调用被称为预检请求。
**我说的几乎是因为常规电话和CORS电话之间还有其他区别。 一个重要的问题是,如果浏览器中没有包含某些标题(即使存在于响应中),它们将不会被Access-Control-Expose-Headers
如果它们不包含在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
)添加到服务器的响应中。 (每个服务器/语言都有办法做到这一点 – 在这里查看一些解决方案 。)
最后的手段:如果您没有对服务的服务器端访问权限,您也可以对其进行镜像(通过反向代理等工具),并在其中包含所有必要的标头。
如果您的服务器上启用了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似乎不介意,如果这个网址是从不同的起源。 就像我说的那样,这是一个拙劣的答案,我确定它有什么问题,但对我来说很有用。
编辑:如果你想在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; ?>
缓存代码从这里获取 。