Access-Control-Allow-Origin头文件如何工作?

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

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

那么,我错了。 这根本就不行。 因此,我已经阅读了跨源资源共享,并尝试在w3c推荐中阅读跨源资源共享

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

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

PS

我不想使用JSONP。

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

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

对于站点B想要访问站点A的每个资源/页面,站点B应该使用响应标头来为其页面提供服务:

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

现代浏览器不会直接阻止跨域请求。 如果站点A从站点B请求一个页面,浏览器实际上将在networking级上获取请求的页面并检查响应标题是否将站点A列为允许的请求者域。 如果站点B没有指出站点A被允许访问该页面,浏览器将触发XMLHttpRequesterror事件,并拒绝响应数据到发出请求的JavaScript代码。

非简单的请求

networking层面发生的事情可能会比上面解释的稍微复杂一些。 如果请求是“非简单”请求 ,浏览器首先发送一个无数据“预检”OPTIONS请求,以validation服务器是否接受请求。 当(或两者)中的一个请求是非简单的:

  • 使用GET或POST以外的HTTP动词(例如PUT,DELETE)
  • 使用非简单的请求标题; 唯一简单的请求标题是:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (当它的值是application/x-www-form-urlencodedmultipart/form-datatext/plain时,这只是简单的)

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

假设站点A想要为/somePage发送一个PUT请求,并且使用一个非简单的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 。

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

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

那些棘手的方法有或多或less的一些问题,例如JSONP可能会导致安全漏洞,如果开发人员简单地“评估”它,上面#3,虽然它的工作,两个域之间应build立严格的契约,它既不灵活也不雅恕我直言:)

W3C引入了跨源资源共享(CORS)作为标准解决scheme,为解决这个问题提供了安全,灵活和推荐的标准方法。

机制

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

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 

我在上面标记的蓝色部分是内核事实,“源”请求标题“指示了跨源请求或预检请求源自的位置”,“访问控制允许源”响应标头指示该页面允许来自远程请求DomainA(如果值为*表示允许来自任何域的远程请求)。

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

 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请求的域时,浏览器才会满足这个条件,提交实际的跨域请求,并caching结果在“ 预检结果caching ”中。

我在三年前就博客了CORS: AJAX Cross-Origin HTTP请求

问题有点太旧了,但是我发布了这个问题以备将来参考。

根据这个 Mozilla开发者networking文章,

当一个资源从一个不同的域请求一个资源,或者一个端口比第一个资源本身服务的资源时,资源会产生一个跨域的HTTP请求

在这里输入图像描述

http://domain-a.com提供的HTML页面http://domain-a.com发送<img> src请求。
今天networking上的许多页面都会加载像CSS样式表图像和来自不同域的脚本资源(因此它应该很酷)。

同源政策

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

跨源资源共享(CORS)

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

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

CORS如何工作( Access-Control-Allow-Origin头)

维基百科 :

CORS标准描述了新的HTTP标头,它为浏览器和服务器提供了一种只有当他们有权限才能请求远程URL的方法。

尽pipe服务器可以执行一些validation和授权, 但是浏览器一般都有责任支持这些标头,并遵守它们所施加的限制。

  1. 浏览器发送一个Origin HTTP头的OPTIONS请求。

    这个头的值是服务父页面的域。 当http://www.example.com的网页尝试访问service.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: *

如果您只想testing浏览器阻止您的请求的跨域应用程序,那么您可以在不安全的模式下打开浏览器并testing您的应用程序,而无需更改您的代码,也不会使您的代码不安全。 从MAC OS你可以从terminal线上做到这一点:

 open -a Google\ Chrome --args --disable-web-security --user-data-dir 

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

下载代码 – 你的HTML脚本标签或从JavaScript或xhr的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:头发送string…但是…为了安全起见,如果你害怕黑客,你的服务器应该只允许在一个名单上,允许这些请求的来源。

然后,MyCode.js来自siteA。 当它向siteB发出请求时,它们都是交叉源的,浏览器发送Origin:siteA,siteB必须接受siteA,将其识别在允许的请求者列表中,然后发回ACAO:siteA。 只有这样,浏览器才能让你的脚本得到这些请求的结果。

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

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

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

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

如果您正在使用PHP,请尝试在php文件的旁边添加以下代码:

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

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

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

 header("Access-Control-Allow-Origin: http://www.website.com"); 

我工作与快递4和节点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 }); 

祝你好运。

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

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

只要通过添加代理链接将工作,但它也可以抛出错误再次无法访问。 因此更好地添加标题如下所示。

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