Access-Control-Allow-Origin头文件如何工作?
显然,我完全误解了它的语义。 我想到了这样的事情:
- 客户端从http:// siteA下载JavaScript代码MyCode.js – 来源 。
- MyCode.js的响应头包含Access-Control-Allow-Origin:http:// siteB ,我认为这意味着MyCode.js被允许对站点B进行跨源引用。
- 客户端触发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被允许访问该页面,浏览器将触发XMLHttpRequest
的error
事件,并拒绝响应数据到发出请求的JavaScript代码。
非简单的请求
networking层面发生的事情可能会比上面解释的稍微复杂一些。 如果请求是“非简单”请求 ,浏览器首先发送一个无数据“预检”OPTIONS请求,以validation服务器是否接受请求。 当(或两者)中的一个请求是非简单的:
- 使用GET或POST以外的HTTP动词(例如PUT,DELETE)
- 使用非简单的请求标题; 唯一简单的请求标题是:
-
Accept
-
Accept-Language
-
Content-Language
-
Content-Type
(当它的值是application/x-www-form-urlencoded
,multipart/form-data
或text/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-Method
和Access-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了许多棘手的方法来实现跨域资源请求,最常用的方法是:
- 使用Flash / Silverlight或服务器端作为“代理”与远程进行通信。
- JSON与填充( JSONP )。
- 将远程服务器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请求。
例如, XMLHttpRequest
和Fetch
遵循同源策略 。
因此,使用XMLHttpRequest
或Fetch
的Web应用程序只能向自己的域发出HTTP请求 。
跨源资源共享(CORS)
为了改进Web应用程序,开发人员要求浏览器供应商允许跨域请求。
跨源资源共享(CORS)机制为Web服务器提供跨域访问控制 ,从而实现安全的跨域数据传输。
现代浏览器在API容器中使用CORS (如XMLHttpRequest
或Fetch
)来缓解跨源HTTP请求的风险。
CORS如何工作( Access-Control-Allow-Origin
头)
维基百科 :
CORS标准描述了新的HTTP标头,它为浏览器和服务器提供了一种只有当他们有权限才能请求远程URL的方法。
尽pipe服务器可以执行一些validation和授权, 但是浏览器一般都有责任支持这些标头,并遵守它们所施加的限制。
例
-
浏览器发送一个
Origin HTTP
头的OPTIONS
请求。这个头的值是服务父页面的域。 当
http://www.example.com
的网页尝试访问service.example.com
的用户数据时,会将以下请求标service.example.com
送到service.example.com
:起源: http : //www.example.com
-
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 });
祝你好运。
使用React和Axios ,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); }