本文翻译自:How does Access-Control-Allow-Origin header work?
Apparently, I have completely misunderstood its semantics. 显然,我完全误解了它的语义。 I thought of something like this: 我想到了这样的事情:
- A client downloads javascript code MyCode.js from http://siteA - the origin . 客户端从http:// siteA- origin下载javascript代码MyCode.js。
- The response header of MyCode.js contains Access-Control-Allow-Origin: http://siteB , which I thought meant that MyCode.js was allowed to make cross-origin references to the site B. MyCode.js的响应标头包含Access-Control-Allow-Origin:http:// siteB ,我认为这意味着MyCode.js被允许对站点B进行跨域引用。
- The client triggers some functionality of MyCode.js, which in turn make requests to http://siteB, which should be fine, despite being cross-origin requests. 客户端触发了MyCode.js的某些功能,该功能继而向http:// siteB发出了请求,尽管这是跨域请求,但仍然可以。
Well, I am wrong. 好吧,我错了。 It does not work like this at all. 它根本不像这样工作。 So, I have read Cross-origin resource sharing and attempted to read Cross-Origin Resource Sharing in w3c recommendation 因此,我阅读了跨域资源共享,并尝试阅读w3c建议中的跨域资源共享
One thing is sure - I still do not understand how am I supposed to use this header. 可以确定的一件事-我仍然不明白我应该如何使用此标头。
I have full control of both site A and site B. How do I enable the javascript code downloaded from the site A to access resources on the site B using this header? 我对站点A和站点B都拥有完全控制权。如何使用此标头使从站点A下载的javascript代码能够访问站点B上的资源?
PS 聚苯乙烯
I do not want to utilize JSONP. 我不想利用JSONP。
#1楼
参考:https://stackoom.com/question/id4F/Access-Control-Allow-Origin标头如何工作
#2楼
Access-Control-Allow-Origin
is a CORS (Cross-Origin Resource Sharing) header . Access-Control-Allow-Origin
是CORS(跨源资源共享)标头 。
When Site A tries to fetch content from Site B, Site B can send an Access-Control-Allow-Origin
response header to tell the browser that the content of this page is accessible to certain origins. 当站点A尝试从站点B获取内容时,站点B可以发送Access-Control-Allow-Origin
响应标头,以告知浏览器某些原始来源可以访问此页面的内容。 (An origin is a domain, plus a scheme and port number .) By default, Site B's pages are not accessible to any other origin ; ( 来源是域,再加上方案和端口号 。)默认情况下, 其他任何来源都无法访问站点B的页面。 using the Access-Control-Allow-Origin
header opens a door for cross-origin access by specific requesting origins. 使用Access-Control-Allow-Origin
标头会打开一扇门,可以通过特定的请求来源进行跨域访问。
For each resource/page that Site B wants to make accessible to Site A, Site B should serve its pages with the response header: 对于站点B希望站点A可以访问的每个资源/页面,站点B应在其页面上提供响应标头:
Access-Control-Allow-Origin: http://siteA.com
Modern browsers will not block cross-domain requests outright. 现代浏览器不会完全阻止跨域请求。 If Site A requests a page from Site B, the browser will actually fetch the requested page on the network level and check if the response headers list Site A as a permitted requester domain. 如果站点A从站点B请求页面,则浏览器实际上将在网络级别获取请求的页面,并检查响应头是否将站点A列为允许的请求者域。 If Site B has not indicated that Site A is allowed to access this page, the browser will trigger the XMLHttpRequest
's error
event and deny the response data to the requesting JavaScript code. 如果站点B未指示允许站点A访问此页面,则浏览器将触发XMLHttpRequest
的error
事件,并拒绝对请求JavaScript代码的响应数据。
Non-simple requests 非简单请求
What happens on the network level can be slightly more complex than explained above. 什么发生在网络层面可以比上述解释稍微复杂一些 。 If the request is a "non-simple" request , the browser first sends a data-less "preflight" OPTIONS request, to verify that the server will accept the request. 如果该请求是“非简单”请求 ,则浏览器将首先发送一个无数据的“预检” OPTIONS请求,以验证服务器将接受该请求。 A request is non-simple when either (or both): 当一个(或两个)同时发生时,请求是不简单的:
- using an HTTP verb other than GET or POST (eg PUT, DELETE) 使用GET或POST以外的HTTP动词(例如PUT,DELETE)
- using non-simple request headers; 使用非简单的请求标头; the only simple requests headers are: 仅有的简单请求标头是:
-
Accept
-
Accept-Language
-
Content-Language
-
Content-Type
(this is only simple when its value isapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
)Content-Type
(仅当其值为application/x-www-form-urlencoded
,multipart/form-data
或text/plain
时,这才简单)
-
If the server responds to the OPTIONS preflight with appropriate response headers ( Access-Control-Allow-Headers
for non-simple headers, Access-Control-Allow-Methods
for non-simple verbs) that match the non-simple verb and/or non-simple headers, then the browser sends the actual request. 如果服务器使用适当的响应标头(非简单标头的Access-Control-Allow-Headers
,非简单动词的Access-Control-Allow-Methods
)响应非简单动词和/或非匹配的OPTIONS预检响应-simple标头,然后浏览器发送实际请求。
Supposing that Site A wants to send a PUT request for /somePage
, with a non-simple Content-Type
value of application/json
, the browser would first send a preflight request: 假设站点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
Note that Access-Control-Request-Method
and Access-Control-Request-Headers
are added by the browser automatically; 请注意,浏览器会自动添加Access-Control-Request-Method
和Access-Control-Request-Headers
。 you do not need to add them. 您无需添加它们。 This OPTIONS preflight gets the successful response headers: 该OPTIONS预检获取成功的响应头:
Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
When sending the actual request (after preflight is done), the behavior is identical to how a simple request is handled. 发送实际请求时(完成预检后),其行为与处理简单请求的方式相同。 In other words, a non-simple request whose preflight is successful is treated the same as a simple request (ie, the server must still send Access-Control-Allow-Origin
again for the actual response). 换句话说,将预检成功的非简单请求与简单请求视为相同(即,服务器必须仍然为实际响应再次发送Access-Control-Allow-Origin
)。
The browsers sends the actual request: 浏览器发送实际请求:
PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json
{ "myRequestContent": "JSON is so great" }
And the server sends back an Access-Control-Allow-Origin
, just as it would for a simple request: 然后服务器发送一个Access-Control-Allow-Origin
,就像处理一个简单的请求一样:
Access-Control-Allow-Origin: http://siteA.com
See Understanding XMLHttpRequest over CORS for a little more information about non-simple requests. 有关非简单请求的更多信息,请参阅通过CORS理解XMLHttpRequest 。
#3楼
Cross-Origin Request Sharing - CORS
(AKA Cross-Domain AJAX request) is an issue that most web developers might encounter, according to Same-Origin-Policy, browsers restrict client JavaScript in a security sandbox, usually JS cannot directly communicate with a remote server from a different domain. 跨域请求共享-根据Same-Origin-Policy, CORS
(AKA跨域AJAX请求)是大多数Web开发人员可能遇到的问题,浏览器将客户端JavaScript限制在安全沙箱中,通常JS无法直接与远程通信来自其他域的服务器。 In the past developers created many tricky ways to achieve Cross-Domain resource request, most commonly using ways are: 过去,开发人员创建了许多棘手的方法来实现跨域资源请求,最常用的方法是:
- Use Flash/Silverlight or server side as a "proxy" to communicate with remote. 使用Flash / Silverlight或服务器端作为“代理”与远程通信。
- JSON With Padding ( JSONP ). 带有填充的JSON( JSONP )。
- Embeds remote server in an iframe and communicate through fragment or window.name, refer here . 将远程服务器嵌入到iframe中,并通过fragment或window.name进行通信,请参见此处 。
Those tricky ways have more or less some issues, for example JSONP might result in security hole if developers simply "eval" it, and #3 above, although it works, both domains should build strict contract between each other, it neither flexible nor elegant IMHO:) 这些棘手的方式或多或少都存在一些问题,例如,如果开发人员只是简单地“评估”,JSONP可能会导致安全漏洞;以及上面的#3,尽管它起作用了,但两个域之间应该建立严格的契约,既不灵活也不优雅恕我直言:)
W3C had introduced Cross-Origin Resource Sharing (CORS) as a standard solution to provide a safe, flexible and a recommended standard way to solve this issue. W3C引入了跨域资源共享(CORS)作为标准解决方案,以提供安全,灵活和推荐的标准方式来解决此问题。
The Mechanism 机制
From a high level we can simply deem CORS is a contract between client AJAX call from domain A and a page hosted on domain B, a typical Cross-Origin request/response would be: 从较高的层次上,我们可以简单地认为CORS是域A的客户端AJAX调用与域B上托管的页面之间的合同,典型的跨域请求/响应为:
DomainA AJAX request headers 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 response headers 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
The blue parts I marked above were the kernal facts, "Origin" request header "indicates where the cross-origin request or preflight request originates from", the "Access-Control-Allow-Origin" response header indicates this page allows remote request from DomainA (if the value is * indicate allows remote requests from any domain). 我在上面标记的蓝色部分是核心事实,“ Origin”请求标头“指示跨域请求或预检请求的来源”,“ Access-Control-Allow-Origin”响应标头指示此页面允许来自远程请求DomainA(如果值为*,则表示允许来自任何域的远程请求)。
As I mentioned above, W3 recommended browser to implement a " preflight request " before submiting the actually Cross-Origin HTTP request, in a nutshell it is an HTTP OPTIONS
request: 正如我上面提到的,W3建议浏览器在提交实际的跨域HTTP请求之前实现一个“ 预检请求 ”,简而言之,它是一个HTTP OPTIONS
请求:
OPTIONS DomainB.com/foo.aspx HTTP/1.1
If foo.aspx supports OPTIONS HTTP verb, it might return response like below: 如果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
Only if the response contains "Access-Control-Allow-Origin" AND its value is "*" or contain the domain who submitted the CORS request, by satisfying this mandtory condition browser will submit the actual Cross-Domain request, and cache the result in " Preflight-Result-Cache ". 仅当响应包含“ Access-Control-Allow-Origin”并且其值为“ *”或包含提交CORS请求的域时,通过满足此强制性条件,浏览器将提交实际的跨域请求,并缓存结果在“ 预检结果缓存 ”中。
I blogged about CORS three years ago: AJAX Cross-Origin HTTP request 我三年前写了关于CORS的博客: AJAX跨源HTTP请求
#4楼
1. A client downloads javascript code MyCode.js from http://siteA - the origin. 1.客户端从源地址http:// siteA下载javascript代码MyCode.js。
The code that does the downloading - your html script tag or xhr from javascript or whatever - came from, let's say, http://siteZ . 进行下载的代码-您的html脚本标记或来自javascript的xhr或其他内容-假设来自http:// siteZ 。 And, when the browser requests MyCode.js, it sends an Origin: header saying "Origin: http://siteZ ", because it can see that you're requesting to siteA and siteZ != siteA. 并且,当浏览器请求MyCode.js时,它将发送一个Origin:标头, 标明 “ Origin: http:// siteZ ”,因为它可以看到您正在请求siteA和siteZ!= siteA。 (You cannot stop or interfere with this.) (您不能停止或干预。)
2. The response header of MyCode.js contains Access-Control-Allow-Origin: http://siteB , which I thought meant that MyCode.js was allowed to make cross-origin references to the site B. 2. MyCode.js的响应标头包含Access-Control-Allow-Origin: http:// siteB ,我认为这意味着MyCode.js被允许对站点B进行跨域引用。
no. 没有。 It means, Only siteB is allowed to do this request. 这意味着,仅siteB被允许执行此请求。 So your request for MyCode.js from siteZ gets an error instead, and the browser typically gives you nothing. 因此,您从siteZ请求MyCode.js时会出错,浏览器通常什么也没有给您。 But if you make your server return ACAO: siteZ instead, you'll get MyCode.js . 但是,如果使服务器返回ACAO:siteZ,则将获得MyCode.js。 Or if it sends '*', that'll work, that'll let everybody in. Or if the server always sends the string from the Origin: header... but... for security, if you're afraid of hackers, your server should only allow origins on a shortlist, that are allowed to make those requests. 或者,如果它发送“ *”,那么它将起作用,它将允许所有人进入。或者,如果服务器始终从Origin:标头发送字符串,但是...出于安全考虑,如果您担心黑客的话,您的服务器应只允许允许进入这些请求的候选清单中的来源。
Then, MyCode.js comes from siteA. 然后,MyCode.js来自siteA。 When it makes requests to siteB, they are all cross-origin, the browser sends Origin: siteA, and siteB has to take the siteA, recognize it's on the short list of allowed requesters, and send back ACAO: siteA. 当它向siteB发出请求时,它们都是跨域的,浏览器将发送Origin:siteA,并且siteB必须使用siteA,将其识别为允许的简短请求者列表,然后发送回ACAO:siteA。 Only then will the browser let your script get the result of those requests. 只有这样,浏览器才会让您的脚本获取这些请求的结果。
#5楼
For cross origin sharing, set header: 'Access-Control-Allow-Origin':'*';
对于跨源共享,请设置标头: 'Access-Control-Allow-Origin':'*';
Php: header('Access-Control-Allow-Origin':'*');
Php: header('Access-Control-Allow-Origin':'*');
Node: app.use('Access-Control-Allow-Origin':'*');
节点: app.use('Access-Control-Allow-Origin':'*');
This will allow to share content for different domain. 这将允许共享不同域的内容。
#6楼
If you are using PHP, try adding the following code at the beginning of the php file: 如果您使用的是PHP,请尝试在php文件的开头添加以下代码:
If you are using localhost, try this: 如果使用本地主机,请尝试以下操作:
header("Access-Control-Allow-Origin: *");
If you are using external domains such as server, try this: 如果使用服务器等外部域,请尝试以下操作:
header("Access-Control-Allow-Origin: http://www.website.com");