问题 基本的AJAX请求获得“No'Access-Control-Allow-Origin'标头出现在请求的资源上”错误


我试图发一个简单的 GET 请求jQuery AJAX请求中的某个链接。

这是一个非常简单的:

$.ajax({
    type: 'GET',
    url: /* <the link as string> */,
    dataType: 'text/html',
    success: function() { alert("Success"); },
    error: function() { alert("Error"); },
});

然而,无论我尝试过什么,我都得到了 XMLHttpRequest cannot load <page>. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:7776' is therefore not allowed access.

我尝试了一切,从添加 header : {} AJAX设置请求的定义 dataType 至 JSONP, 甚至 text/plain使用简单的AJAX而不是jQuery,甚至下载一个支持CORS的插件 - 但没有什么可以帮助。

如果我试图访问任何其他网站,也会发生同样的情况。

有关正确和简单解决方案的任何想法?有没有?


2676
2018-02-10 00:28


起源

您不能向另一个域发出ajax请求,因为CORS(跨源资源共享),除非另一个域(在本例中为stackoverflow)允许它。 - Pipe
你无法单独在浏览器上绕过同源策略,因为它会彻底破坏它的目的。 - JJJ
@Juhana,答案是 也 来自Stack Overflow! - Zoltán Schmidt
不知道你想说什么,但还可以。 - JJJ
@Juhana您的评论意味着浏览器插件是解决此问题的荒谬且荒谬的方法。我强调这样做的想法也来自这个网站,我认为即使在这里,也可以在没有低估的情况下给出可怕的答案。这很难过,但我当然不是在判断网站的质量。 - Zoltán Schmidt


答案:


这是设计的。您不能使用XMLHttpRequest向另一台服务器发出任意HTTP请求,除非该服务器通过为请求主机发出Access-Control-Allow-Origin标头来允许它。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

您可以在脚本标记中检索它(对脚本和图像以及样式表没有相同的限制),但除非返回的内容是脚本,否则它对您没有多大帮助。

这是一篇关于CORS的教程:

http://www.bennadel.com/blog/2327-cross-origin-resource-sharing-cors-ajax-requests-between-jquery-and-node-js.htm

这样做是为了保护最终用户。假设一个图像实际上是一个图像,样式表只是一个样式表,而一个脚本只是一个脚本,从另一个服务器请求这些资源实际上不会造成任何伤害。

但总的来说,跨域请求可以做很糟糕的事情。说你,Zoltan,正在使用coolsharks.com。另请注意,您已登录mybank.com并且浏览器中有mybank.com的cookie。现在,假设coolsharks.com向mybank.com发送了一个AJAX请求,要求将所有资金转入另一个帐户。因为您存储了mybank.com cookie,所以他们成功完成了请求。所有这些都是在您不知情的情况下发生的,因为没有发生页面重新加载。这是允许一般跨站点AJAX请求的危险。

如果要执行跨站点请求,您有两种选择:

  1. 获取您要求的服务器
    一个。通过推出包含您(或*)的Access-Control-Allow-Origin标头来承认
    湾为您提供JSONP API。

要么

  1. 编写自己的浏览器,不符合标准,没有任何限制。

在(1)中,您必须与您要求的服务器合作,并且在(2)中,您必须控制最终用户的浏览器。如果你不能满足(1)或(2),你几乎没有运气。

但是,还有第三种选择(charlietfl指出)。您可以从您控制的服务器发出请求,然后将结果传回页面。例如。

<script>
$.ajax({
    type: 'GET',
    url: '/proxyAjax.php?url=http%3A%2F%2Fstackoverflow.com%2F10m',
    dataType: 'text/html',
    success: function() { alert("Success"); },
    error: function() { alert("Error"); }
});
</script>

然后在您的服务器上,最简单的:

<?php
// proxyAjax.php
// ... validation of params
// and checking of url against whitelist would happen here ...
// assume that $url now contains "http://stackoverflow.com/10m"
echo file_get_contents($url);

当然,这种方法可能遇到其他问题:

  • 您是代理的网站是否需要正确的推荐人或某个IP地址?
  • cookie是否需要传递到目标服务器?
  • 您的白名单是否足以保护您免受任意请求的影响?
  • 当您的服务器接收到哪些标题(例如修改时间等)时,您将返回浏览器,哪些标题将被省略或更改?
  • 您的服务器是否会因为提出非法请求而受到牵连(因为您作为代理人)?

我确定还有其他人。但如果这些问题都没有阻止它,那么第三种方法可以很好地发挥作用。


7
2018-02-10 00:44



缺少#3,它使用您控制的域上的代理来发出请求并返回所需资源 - charlietfl
@charlietfl非常好的一点,我忘了那个选项。 - Chris Middleton
然后有像Yahoo YQL这样的第三方代理 - charlietfl
@Zoltan。是的,在不使用代理的情况下,在尝试从热门网站请求网页时,获取JSONP API将是您最好的选择。 (他们不太可能将你的起源或*放在他们的标题中。)但请记住,通常不会为请求站点的任意可导航页面(例如问题中的“/ 10m”链接)创建JSONP API )。它通常用于接收JSON而不是HTML的地方。 - Chris Middleton
因此,有些网站是我永远无法做到的 GET 在任何情况下,我都对吗?当然没有代理。 - Zoltán Schmidt


您可以询问该域的开发人员是否会为您设置合适的标头,此限制仅适用于javascript,基本上您可以使用php或其他任何方式从您的服务器请求ressource,然后javascript请求您的域中的数据


3
2018-02-10 00:34



如果 - 在这种特殊情况下 - 我通过SE API验证自己,这有帮助吗? - Zoltán Schmidt
我不知道这个api,但是如果提供商提供了一个用于javascript使用的api,那么他们最可能提供一个可以使用js请求的api - john Smith