1401

显然,我完全误解了它的语义。我想到了这样的事情:

  1. http://siteA客户端从下载 javascript 代码 MyCode.js 。
  2. MyCode.js 的响应头包含Access-Control-Allow-Origin:http://siteB,我认为这意味着 MyCode.js 被允许对站点 B 进行跨域引用。
  3. 客户端触发了 MyCode.js 的一些功能,这些功能反过来向 .js 发出请求http://siteB,这应该没问题,尽管是跨域请求。

好吧,我错了。它根本不像这样工作。所以,我已经阅读了跨域资源共享并尝试阅读w3c 推荐中的跨域资源共享

有一件事是肯定的——我仍然不明白我应该如何使用这个标题。

我可以完全控制站点 A 和站点 B。如何启用从站点 A 下载的 javascript 代码以使用此标头访问站点 B 上的资源?

附言

我不想使用 JSONP。

4

18 回答 18

1704

Access-Control-Allow-Origin是一个CORS(跨域资源共享)标头

当站点 A 尝试从站点 B 获取内容时,站点 B 可以发送一个Access-Control-Allow-Origin响应标头来告诉浏览器该页面的内容可以从某些来源访问。(是一个域,加上一个方案和端口号。)默认情况下,任何其他源都无法访问站点 B 的页面;使用Access-Control-Allow-Origin标头为特定请求来源的跨域访问打开了一扇门。

对于站点 B 希望站点 A 可以访问的每个资源/页面,站点 B 应为其页面提供响应标头:

Access-Control-Allow-Origin: http://siteA.com

现代浏览器不会直接阻止跨域请求。如果站点 A 从站点 B 请求页面,浏览器实际上将在网络级别获取请求的页面,并检查响应标头是否将站点 A 列为允许的请求者域。如果站点 B 没有表明允许站点 A 访问该页面,浏览器将触发XMLHttpRequest'error事件并拒绝对请求 JavaScript 代码的响应数据。

非简单请求

网络级别发生的事情可能上面解释的要复杂一些。如果请求是“非简单”请求,浏览器首先发送一个无数据的“预检”OPTIONS 请求,以验证服务器是否会接受该请求。当任一(或两者)时,请求是非简单的:

  • 使用 GET 或 POST 以外的 HTTP 动词(例如 PUT、DELETE)
  • 使用非简单的请求头;唯一简单的请求标头是:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type(仅当它的值为 、 或 时才application/x-www-form-urlencodedmultipart/form-data简单text/plain

如果服务器使用与非简单动词和/或非简单标头匹配的适当响应标头(Access-Control-Allow-Headers对于非简单标头,对于非简单动词)响应 OPTIONS 预检,则浏览器发送实际请求。Access-Control-Allow-Methods

假设站点 A 想要发送一个 PUT 请求/somePage,其非简单Content-Type值为application/json,浏览器将首先发送一个预检请求:

OPTIONS /somePage HTTP/1.1
Origin: http://siteA.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

注意Access-Control-Request-MethodAccess-Control-Request-Headers是由浏览器自动添加的;您不需要添加它们。此 OPTIONS 预检获取成功的响应标头:

Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type

发送实际请求时(预检完成后),其行为与处理简单请求的方式相同。换句话说,预检成功的非简单请求被视为与简单请求相同(即,服务器仍必须Access-Control-Allow-Origin再次发送实际响应)。

浏览器发送实际请求:

PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json

{ "myRequestContent": "JSON is so great" }

并且服务器发回一个Access-Control-Allow-Origin,就像它对一个简单的请求一样:

Access-Control-Allow-Origin: http://siteA.com

有关非简单请求的更多信息,请参阅了解 CORS 上的 XMLHttpRequest 。

于 2012-05-17T13:33:26.440 回答
140

跨域资源共享 - CORS(AKA 跨域 AJAX 请求)是大多数 Web 开发人员可能遇到的问题,根据 Same-Origin-Policy,浏览器将客户端 JavaScript 限制在安全沙箱中,通常 JS 无法直接与远程服务器通信来自不同的域。过去开发人员创造了许多棘手的方法来实现跨域资源请求,最常用的方法有:

  1. 使用 Flash/Silverlight 或服务器端作为“代理”与远程通信。
  2. 带填充的 JSON ( JSONP )。
  3. 将远程服务器嵌入 iframe 并通过片段或 window.name 进行通信,请参阅此处

这些棘手的方法或多或少都有一些问题,例如如果开发人员简单地“评估”它,JSONP 可能会导致安全漏洞,以及上面的#3,虽然它有效,但两个域应该在彼此之间建立严格的契约,它既不灵活也不优雅恕我直言:)

W3C 引入了跨域资源共享 (CORS) 作为标准解决方案,以提供安全、灵活和推荐的标准方法来解决此问题。

机制

从高层次上,我们可以简单地认为 CORS 是来自域 A 的客户端 AJAX 调用与域 B 上托管的页面之间的合约,典型的跨域请求/响应将是:

DomainA AJAX 请求标头

Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com 

DomainB 响应标头

Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive

我上面标记的蓝色部分是核心事实,“Origin”请求标头“指示跨域请求或预检请求的来源”,“Access-Control-Allow-Origin”响应标头指示此页面允许远程请求来自DomainA(如果值为 * 表示允许来自任何域的远程请求)。

正如我上面提到的,W3 建议浏览器在提交实际的跨域 HTTP 请求之前实现“预检请求OPTIONS”,简而言之就是一个 HTTP请求:

OPTIONS DomainB.com/foo.aspx HTTP/1.1

如果 foo.aspx 支持 OPTIONS HTTP 动词,它可能会返回如下响应:

HTTP/1.1 200 OK
Date: Wed, 01 Mar 2011 15:38:19 GMT
Access-Control-Allow-Origin: http://DomainA.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Max-Age: 1728000
Connection: Keep-Alive
Content-Type: application/json

只有当响应包含“Access-Control-Allow-Origin”且值为“*”或包含提交CORS请求的域时,满足此强制条件,浏览器才会提交实际的跨域请求,并缓存结果在“预检结果缓存”中。

三年前我写过关于 CORS 的博客:AJAX Cross-Origin HTTP request

于 2014-01-23T13:54:54.860 回答
85

问题有点太老了,无法回答,但我发布这个以供将来参考这个问题。

根据这篇Mozilla 开发者网络文章,

当资源从与第一个资源本身服务的域或端口不同的域或端口请求资源时,它会发出跨域 HTTP 请求。

在此处输入图像描述

从提供的HTML 页面http://domain-a.com发出<img>src 请求http://domain-b.com/image.jpg
今天网络上的许多页面从不同的域加载资源,如CSS 样式表图像脚本(因此它应该很酷)。

同源策略

出于安全原因,浏览器限制从脚本中发起的跨域 HTTP请求。 例如,并遵循同源策略。 因此,使用或只能向其自己的域发出HTTP请求Web 应用程序。
XMLHttpRequestFetch
XMLHttpRequestFetch

跨域资源共享 (CORS)

为了改进 Web 应用程序,开发人员要求浏览器供应商允许跨域请求。

跨域资源共享 (CORS)机制为 Web 服务器提供跨域访问控制,从而实现安全的跨域数据传输。
现代浏览器在API 容器中使用CORS - 例如或- 来降低跨域 HTTP 请求的风险。XMLHttpRequestFetch

CORS 的工作原理(Access-Control-Allow-Origin标题)

维基百科

CORS 标准描述了新的 HTTP 标头,它为浏览器和服务器提供了一种仅在获得许可时才请求远程 URL 的方法。

尽管服务器可以执行一些验证和授权,但通常浏览器有责任支持这些标头并遵守它们施加的限制。

例子

  1. 浏览器发送OPTIONS带有Origin HTTP标头的请求。

    此标头的值是为父页面提供服务的域。当一个页面http://www.example.com尝试访问 中的用户数据时service.example.com,以下请求标头将被发送到service.example.com

    来源:http ://www.example.com

  2. 服务器service.example.com可能会响应:

    • 响应中的Access-Control-Allow-Origin(ACAO) 标头指示允许哪些源站点。
      例如:

      Access-Control-Allow-Origin: http://www.example.com

    • 如果服务器不允许跨域请求,则会出现错误页面

    • Access-Control-Allow-Origin带有通配符的(ACAO) 标头,允许所有域:

      Access-Control-Allow-Origin: *

于 2017-03-05T06:39:53.727 回答
38

每当我开始考虑 CORS 时,我对哪个站点托管标头的直觉是不正确的,正如您在问题中所描述的那样。对我来说,考虑同源政策的目的是有帮助的。

同源策略的目的是保护您免受 siteA.com 上的恶意 JavaScript 访问您选择仅与 siteB.com 共享的私人信息。如果没有同源策略,siteA.com 的作者编写的 JavaScript 可能会使用您对 siteB.com 的身份验证 cookie 使您的浏览器向 siteB.com 发出请求。这样,siteA.com 就可以窃取您与 siteB.com 共享的秘密信息。

有时您需要跨域工作,这就是 CORS 的用武之地。CORS 放宽了 siteB.com 的同源策略,使用Access-Control-Allow-Origin标头列出受信任运行可与 siteB 交互的 JavaScript 的其他域 (siteA.com)。 com。

要了解哪个域应该为 CORS 标头提供服务,请考虑这一点。您访问了恶意网站,其中包含一些试图向 mybank.com 发出跨域请求的 JavaScript。应该由 mybank.com 而不是恶意网站来决定它是否设置 CORS 标头以放宽相同的来源策略,从而允许来自恶意网站的 JavaScript 与之交互。如果 malicous.com 可以设置自己的 CORS 标头,允许其自己的 JavaScript 访问 mybank.com,这将完全取消同源策略。

我认为我直觉不好的原因是我在开发网站时的观点。这是的网站,包含所有的JavaScript,因此它没有做任何恶意行为,应该由来指定我的JavaScript 可以与哪些其他网站交互。事实上,我应该考虑哪些其他网站 JavaScript 正在尝试与我的网站交互,我应该使用 CORS 来允许它们吗?

于 2018-01-28T18:47:01.637 回答
17

根据我自己的经验,很难找到一个简单的解释,为什么 CORS 甚至是一个问题。

一旦你理解了它为什么存在,标题和讨论就会变得更加清晰。我会在几行中试一试。


这都是关于饼干的。Cookies 按其域存储在客户端上。

一个示例故事:在您的计算机上,有一个用于yourbank.com. 也许你的会话在那里。

关键点:当客户端向服务器发出请求时,它将为该请求发送存储在域下的 cookie。

您已在浏览器上登录到yourbank.com. 您请求查看您的所有帐户,并为yourbank.com. yourbank.com接收一堆 cookie 并发送回其响应(您的帐户)。

如果另一个客户端向服务器发出跨源请求,这些 cookie 会像以前一样被发送。鲁罗。

您浏览到malicious.com. 恶意向不同的银行发出大量请求,包括yourbank.com.

由于 cookie 按预期进行验证,服务器将授权响应。

这些 cookie 被收集起来并一起发送 - 现在,malicious.com有来自yourbank.

哎呀。


所以现在,一些问题和答案变得显而易见:

  • “我们为什么不直接阻止浏览器这样做呢?” 是的。CORS。
  • “我们如何绕过它?” 让服务器告诉请求 CORS 正常。
于 2019-11-18T19:40:42.480 回答
15

1. 客户端从http://siteA - 来源下载 javascript 代码 MyCode.js 。

进行下载的代码——你的 html 脚本标签或来自 javascript 的 xhr 或其他任何东西——来自http://siteZ。而且,当浏览器请求 MyCode.js 时,它会发送一个 Origin: 标头说“Origin: http://siteZ ”,因为它可以看到您正在向 siteA 和 siteZ 请求!= siteA。(您不能停止或干预。)

2. MyCode.js 的响应头包含 Access-Control-Allow-Origin: http://siteB,我认为这意味着 MyCode.js 被允许对站点 B 进行跨域引用。

不。这意味着,仅允许 siteB 执行此请求。因此,您从 siteZ 对 MyCode.js 的请求反而会收到错误,而浏览器通常不会给您任何信息。但是如果你让你的服务器返回 ACAO: siteZ ,你会得到 MyCode.js 。或者如果它发送'*',那会起作用,这会让每个人都进入。或者如果服务器总是从 Origin: 标头发送字符串......但是......为了安全,如果你害怕黑客,您的服务器应该只允许入围名单上的来源,允许发出这些请求。

然后,MyCode.js 来自 siteA。当它向siteB发出请求时,它们都是跨域的,浏览器发送Origin:siteA,并且siteB必须获取siteA,识别它在允许的请求者的短名单上,然后发回ACAO:siteA。只有这样,浏览器才会让您的脚本获得这些请求的结果。

于 2016-02-27T01:37:43.353 回答
15

使用ReactAxios,将代理链接加入 URL 并添加标题,如下所示

https://cors-anywhere.herokuapp.com/+Your API URL

只需添加代理链接即可,但它也可能再次引发 No Access 错误。因此最好添加标题,如下所示。

axios.get(`https://cors-anywhere.herokuapp.com/[YOUR_API_URL]`,{headers: {'Access-Control-Allow-Origin': '*'}})
      .then(response => console.log(response:data);
  }

警告:不得用于生产

这只是一个快速修复,如果您在为无法获得响应而苦苦挣扎,您可以使用它。但这又不是生产的最佳答案。

得到了几次反对票,这完全有道理,我早就应该添加警告。

于 2017-10-16T15:53:24.213 回答
12

如果您使用的是 PHP,请尝试在 php 文件的开头添加以下代码:

如果您使用的是本地主机,请尝试以下操作:

header("Access-Control-Allow-Origin: *");

如果您使用的是外部域,例如服务器,请尝试以下操作:

header("Access-Control-Allow-Origin: http://www.website.com");
于 2017-01-18T15:30:06.290 回答
12

如果您只想测试浏览器阻止您的请求的跨域应用程序,那么您可以在不安全模式下打开浏览器并测试您的应用程序,而无需更改代码,也不会使您的代码不安全。在 MAC OS 中,您可以从终端行执行此操作:

open -a Google\ Chrome --args --disable-web-security --user-data-dir
于 2017-02-22T16:32:30.393 回答
11

我使用 express 4 和 node 7.4 和 angular,我遇到了同样的问题,我可以帮助解决这个问题:
a)服务器端:在 app.js 文件中,我为所有响应提供标题,例如:

app.use(function(req, res, next) {  
      res.header('Access-Control-Allow-Origin', req.headers.origin);
      res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
      next();
 });  

这在所有路由器之前必须有
我看到很多添加了这个标题:

res.header("Access-Control-Allow-Headers","*");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');

但我不需要那个,
b)客户端:在发送ajax中你需要添加:“withCredentials:true”,比如:

$http({
     method: 'POST',
     url: 'url, 
     withCredentials: true,
     data : {}
   }).then(function(response){
        // code  
   }, function (response) {
         // code 
   });
于 2017-02-06T08:19:11.937 回答
7

在 Python 中,我一直在使用该Flask-CORS并取得了巨大的成功。它使处理 CORS 变得超级简单和轻松。我从下面的库文档中添加了一些代码。

安装:

$ pip install -U flask-cors

允许对所有路由上的所有域进行 CORS 的简单示例:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

有关更具体的示例,请参阅文档。我已经使用上面的简单示例来解决我正在构建的必须访问单独的烧瓶服务器的离子应用程序中的 CORS 问题。

于 2018-01-25T11:10:18.760 回答
4

对于跨域共享,设置标题:'Access-Control-Allow-Origin':'*';

php:header('Access-Control-Allow-Origin':'*');

节点:app.use('Access-Control-Allow-Origin':'*');

这将允许共享不同域的内容。

于 2016-11-28T02:39:37.513 回答
4

只需将以下代码粘贴到您的 web.config 文件中。

请注意,您必须在标签下粘贴以下<system.webServer>代码

    <httpProtocol>  
    <customHeaders>  
     <add name="Access-Control-Allow-Origin" value="*" />  
     <add name="Access-Control-Allow-Headers" value="Content-Type" />  
     <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />  
    </customHeaders>  
  </httpProtocol>  
于 2019-01-20T04:35:59.967 回答
3

我无法在后端服务器中配置它,但浏览器中的这些扩展对我有用:

对于 Firefox: Cors 无处不在

对于 Google Chrome: 允许 CORS:Access-Control-Allow-Origin

注意:CORS 使用此配置为我工作:

允许 CORS 选项

CORS 无处不在的选项

于 2021-03-10T09:49:10.907 回答
2

Nginx 和阿帕奇

作为apsillers 回答的补充,我想添加wiki 图表,显示请求何时简单(以及 OPTIONS 飞行前请求是否发送)

在此处输入图像描述

对于简单的请求(例如热链接图像),您不需要更改服务器配置文件,但您可以在应用程序中添加标头(托管在服务器上,例如在 php 中),如 Melvin Guerrero 在他的回答中提到的- 但请记住:如果您添加完整您的服务器(配置)中的 cors 标头,同时您允许在应用程序(例如 php)上使用简单的 cors,这根本不起作用。

这是两个流行服务器的配置

  • 在 Nginx上开启CORSnginx.conf文件)

    location ~ ^/index\.php(/|$) {
       ...
        add_header 'Access-Control-Allow-Origin' "$http_origin" always; # if you change "$http_origin" to "*" you shoud get same result - allow all domain to CORS (but better change it to your particular domain)
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        if ($request_method = OPTIONS) {
            add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above)
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';  # arbitrary methods
            add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin'; # arbitrary headers
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            return 204;
        }
    }

  • 在 Appache上开启CORS.htaccess文件)

    # ------------------------------------------------------------------------------
    # | Cross-domain Ajax requests                                                 |
    # ------------------------------------------------------------------------------
    
    # Enable cross-origin Ajax requests.
    # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
    # http://enable-cors.org/
    
    # change * (allow any domain) below to your domain
    Header set Access-Control-Allow-Origin "*"
    Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
    Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"
    Header always set Access-Control-Allow-Credentials "true"

于 2020-05-15T09:33:09.143 回答
1

Access-Control-Allow-Origin 响应标头指示响应是否可以与来自给定源的请求代码共享。

Header type Response       header
Forbidden header name      no

告诉浏览器允许来自任何来源的代码访问资源的响应将包括以下内容:

Access-Control-Allow-Origin: *

欲了解更多信息,请访问这里....

于 2019-01-31T11:49:26.977 回答
0

仅用于测试的临时解决方案:

谁不能控制后端Options 405 Method Not Allowed
Chrome 浏览器的解决方法。
在命令行中执行:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="path_to_profile"
示例:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="C:\Users\vital\AppData\Local\Google\Chrome\User Data\Profile 2"

于 2020-06-18T11:30:32.590 回答
0

对于带有 Angular 的 .NET Core 3.1 API

Startup.cs : 添加 CORS

    //SERVICES
    public void ConfigureServices(IServiceCollection services){

        //CORS (Cross Origin Resource Sharing)
        //=====================================
        services.AddCors();
    }

    //MIDDLEWARES
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRouting();

        //ORDER: CORS -> Authentication -> Authorization)
        //CORS (Cross Origin Resource Sharing)
        //=====================================  
        app.UseCors(x=>x.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:4200"));

        app.UseHttpsRedirection();
    }
}

控制器:为授权控制器启用 CORS

 //Authorize all methods inside this controller
 [Authorize]
 [EnableCors()]
 public class UsersController : ControllerBase
 {
    //ActionMethods
 }
于 2021-10-25T17:01:47.100 回答