jQuery XML 错误“请求的资源上不存在”Access-Control-Allow-Origin“标头。

jQuery XML error ' No 'Access-Control-Allow-Origin' header is present on the requested resource.'

提问人:Bazinga777 提问时间:11/7/2013 最后编辑:SyscallBazinga777 更新时间:4/17/2021 访问量:282379

问:

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

到目前为止,我已经想出了下面的代码,这是非常基本的代码,以便读取XML,但是我收到以下错误。

XMLHttpRequest 无法加载 ****。没有“访问控制允许源” 标头存在于请求的资源上。起源 因此,“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');
            }
         });
    }
);

我看不出我的代码有什么问题,所以我希望有人能指出我的代码出了什么问题以及如何修复它。

JavaScript jQuery ajax XML 解析 CORS

评论

2赞 jmoerdyk 11/7/2013
我建议您阅读同源政策CORS
0赞 Kevin B 11/7/2013
错误准确地说明了错误所在,逐字逐句。您的代码很好,问题出在您正在访问的服务器上。
0赞 Amir Ali Akbari 12/2/2013
另请参阅 MDN 上的 CORS

答:

163赞 acdcjunior 11/7/2013 #1

由于同源策略,您将无法从部署在http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xmlhttp://run.jsbin.com


由于源(又名)页面和目标 URL 位于不同的域 ( 和 ),因此您的代码实际上是在尝试发出跨域 (CORS) 请求,而不是普通的 .run.jsbin.comwww.ecb.europa.euGET

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


例:

一个页面只能直接请求位于 的服务,比如 。如果服务托管在另一个域(例如),浏览器不会直接进行调用(如您所料)。相反,它将尝试发出 CORS 请求。http://www.example.com/myPage.htmlhttp://www.example.comhttp://www.example.com/api/myServicehttp://www.ok.com/api/myService

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

  • 将在原始请求中包含一个标头(以页面的域为值)并照常执行;然后Origin
  • 只有当服务器该请求的响应包含允许 CORS 请求的足够标头(Access-Control-Allow-Origin 就是其中之一时,浏览才会完成调用(几乎与 HTML 页面位于同一域时完全相同)。
    • 如果预期的标头没有出现,浏览器就会放弃(就像它对你所做的那样)。


* 以上描述了一个简单的请求中的步骤,例如没有花哨标头的常规 GET。如果请求不简单(例如以 application/json 为内容类型的 POST),浏览器将保留它片刻,并且在完成它之前,将首先向目标 URL 发送 OPTIONS 请求。如上所述,仅当对此 OPTIONS 请求的响应包含 CORS 标头时,它才会继续。此 OPTIONS 调用称为预检请求。
** 我之所以这么说,几乎是因为常规呼叫和 CORS 呼叫之间还有其他区别。一个重要的问题是,如果某些标头未包含在 Access-Control-Expose-Headers 标头中,即使它们存在于响应中,浏览器也不会选取它们。


如何解决?

这只是一个错别字吗?有时,JavaScript 代码在目标域中只有一个拼写错误。你检查过了吗?如果该页面位于该页面,它只会定期调用!其他 URL,例如 or 甚至 or 被浏览器视为不同的域!是的,如果端口不同,那么它就是不同的域!www.example.comwww.example.comapi.example.comexample.comwww.example.com:8080

添加标头。启用 CORS 的最简单方法是将必要的标头 (as ) 添加到服务器的响应中。(每个服务器/语言都有一种方法可以做到这一点 - 在此处查看一些解决方案Access-Control-Allow-Origin

不得已而为之:如果您没有对服务的服务器端访问权限,您还可以镜像它(通过反向代理等工具),并在其中包含所有必要的标头。

评论

2赞 Bazinga777 11/7/2013
谢谢,这是很多信息。现在我可以进行必要的研究以继续进行。
1赞 Franva 4/11/2014
嗨,acdcjunior,如何镜像我想访问的 Web 服务?
2赞 acdcjunior 4/12/2014
@Franva 您必须设置一个 HTTP 服务器(例如 Tomcat、带有 PHP 的 Apache、带有 ASP 的 IIS)并在那里放置一个页面,对于每个请求,它都会打开一个指向实际服务(您正在镜像的服务)的套接字,请求实际数据,然后将其作为响应。当然,您将通过代码(Java、PHP、ASP 等)来做到这一点。
0赞 machinarium 7/17/2014
@acdcjunior如果我的理解正确,请纠正我。如果我直接在浏览器中输入一些 URL,它将自动重定向到新的域 URL,而不会使用 Access-Control-Allow-Origin。例如,使用WIF时,用户在首次登录时会被重定向到第三方登录页面。
0赞 acdcjunior 7/17/2014
@machinarium 我不确定我是否理解你的意思,但我会尝试回答(告诉我我是否做错了):如果您在浏览器的地址栏中输入 URL,则该 URL 标题中的存在与否根本不重要 - 浏览器将像往常一样打开 URL。同源策略(以及标头要求)仅适用于 Ajax 调用。Access-Control-Allow-OriginAccess-Control-Allow-Origin
30赞 jyapayne 12/18/2013 #2

如果您在服务器上启用了 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 似乎并不介意该 url 是否来自不同的来源。就像我说的,这是一个骇人听闻的答案,我确信它有问题,但它对我有用。

编辑: 如果你想在 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;

?>

缓存代码从这里获取。

评论

3赞 sffc 12/28/2013
更好的解决方案是在服务器端缓存 XML 文件,并且仅在最新的 XML 文件已足够过时时才执行调用。另外,不要忘记您的 Content-Type 标头 :-)file_get_contents
0赞 mpdc 10/29/2014
偶然发现了这个答案。问:PHP 文件如何知道获取 GET 数据并将其提交到所述 URL?这也适用于 POST 数据吗?
0赞 Thought 12/18/2015
它不提交它。它获取文件并将其保存在本地,然后将其喷出,就好像该文件是您在本地请求的 php 文件一样。如果本地缓存的文件早于给定的最长期限,它将检索并保存它的另一个副本。