跨源資源共享 (CORS) (或通俗地譯為跨域資源共享)是一種機制,該機制使用附加的 HTTP 頭來告訴浏覽器,準許運作在一個源上的Web應用通路位于另一不同源標明的資源。 當一個Web應用發起一個與自身所在源(域,協定和端口)不同的HTTP請求時,它發起的即跨源HTTP請求。
跨源HTTP請求的一個例子:運作在 http://domain-a.com 的JavaScript代碼使用XMLHttpRequest來發起一個到 https://domain-b.com/data.json 的請求。
出于安全性,浏覽器限制腳本内發起的跨源HTTP請求。 例如,XMLHttpRequest和Fetch API遵循同源政策。 這意味着使用這些API的Web應用程式隻能從加載應用程式的同一個域請求HTTP資源,除非響應封包包含了正确CORS響應頭。
跨源域資源共享( CORS )機制允許 Web 應用伺服器進行跨源通路控制,進而使跨源資料傳輸得以安全進行。現代浏覽器支援在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以降低跨源 HTTP 請求所帶來的風險。
誰應該讀這篇文章?
說實話,每個人。
更具體地來講,這篇文章适用于網站管理者、後端和前端開發者。現代浏覽器處理跨源資源共享的用戶端部分,包括HTTP頭和相關政策的執行。但是這一新标準意味着伺服器需要處理新的請求頭和響應頭。對于服務端的支援,開發者可以閱讀補充材料 cross-origin sharing from a server perspective (with PHP code snippets) 。
什麼情況下需要 CORS ?
這份 cross-origin sharing standard 允許在下列場景中使用跨站點 HTTP 請求:
- 前文提到的由 XMLHttpRequest 或 Fetch 發起的跨源 HTTP 請求。
- Web 字型 (CSS 中通過
使用跨源字型資源),是以,網站就可以釋出 TrueType 字型資源,并隻允許已授權網站進行跨站調用。 @font-face
- WebGL 貼圖
- 使用
将 Images/video 畫面繪制到 canvasdrawImage
本文概述了跨源資源共享機制及其所涉及的 HTTP 頭。
功能概述
跨源資源共享标準新增了一組 HTTP 首部字段,允許伺服器聲明哪些源站通過浏覽器有權限通路哪些資源。另外,規範要求,對那些可能對伺服器資料産生副作用的 HTTP 請求方法(特别是 GET 以外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),浏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),進而獲知服務端是否允許該跨源請求。伺服器确認允許之後,才發起實際的 HTTP 請求。在預檢請求的傳回中,伺服器端也可以通知用戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關資料)。
CORS請求失敗會産生錯誤,但是為了安全,在JavaScript代碼層面是無法獲知到底具體是哪裡出了問題。你隻能檢視浏覽器的控制台以得知具體是哪裡出現了錯誤。
接下來的内容将讨論相關場景,并剖析該機制所涉及的 HTTP 首部字段。
若幹通路控制場景
這裡,我們使用三個場景來解釋跨源資源共享機制的工作原理。這些例子都使用 XMLHttpRequest 對象。
本文中的 JavaScript 代碼片段都可以從 http://arunranga.com/examples/access-control/ 獲得。另外,使用支援跨源 XMLHttpRequest 的浏覽器通路該位址,可以看到代碼的實際運作結果。
關于服務端對跨源資源共享的支援的讨論,請參見這篇文章: Server-Side_Access_Control (CORS)。
簡單請求
某些請求不會觸發 CORS 預檢請求。本文稱這樣的請求為“簡單請求”,請注意,該術語并不屬于 Fetch (其中定義了 CORS)規範。若請求滿足所有下述條件,則該請求可視為“簡單請求”:
- 使用下列方法之一:
- GET
- HEAD
- POST
- 除了被使用者代理自動設定的首部字段(例如 Connection ,User-Agent)和在 Fetch 規範中定義為 禁用首部名稱 的其他首部,允許人為設定的字段為 Fetch 規範定義的 對 CORS 安全的首部字段集合。該集合為:
- Accept
- Accept-Language
- Content-Language
- Content-Type (需要注意額外的限制)
-
DPR
-
Downlink
-
Save-Data
-
Viewport-Width
-
Width
- Content-Type 的值僅限于下列三者之一:
-
text/plain
-
multipart/form-data
-
application/x-www-form-urlencoded
- 請求中的任意XMLHttpRequestUpload 對象均沒有注冊任何事件監聽器;XMLHttpRequestUpload 對象可以使用 XMLHttpRequest.upload 屬性通路。
- 請求中沒有使用 ReadableStream 對象。
注意: 這些跨站點請求與浏覽器發出的其他跨站點請求并無二緻。如果伺服器未傳回正确的響應首部,則請求方不會收到任何資料。是以,那些不允許跨站點請求的網站無需為這一新的 HTTP 通路控制特性擔心。
注意: WebKit Nightly 和 Safari Technology Preview 為Accept, Accept-Language, 和 Content-Language 首部字段的值添加了額外的限制。如果這些首部字段的值是“非标準”的,WebKit/Safari 就不會将這些請求視為“簡單請求”。WebKit/Safari 并沒有在文檔中列出哪些值是“非标準”的,不過我們可以在這裡找到相關讨論:Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language, Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS, and Switch to a blacklist model for restricted Accept headers in simple CORS requests。其它浏覽器并不支援這些額外的限制,因為它們不屬于規範的一部分。
比如說,假如站點 http://foo.example 的網頁應用想要通路 http://bar.other 的資源。http://foo.example 的網頁中可能包含類似于下面的 JavaScript 代碼:
<span style="color:#333333"><code class="language-js"><span style="color:#0077aa">var</span> invocation <span style="color:#9a6e3a">=</span> <span style="color:#0077aa">new</span> <span style="color:#dd4a68">XMLHttpRequest</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#0077aa">var</span> url <span style="color:#9a6e3a">=</span> <span style="color:#669900">'http://bar.other/resources/public-data/'</span><span style="color:#999999">;</span>
<span style="color:#0077aa">function</span> <span style="color:#dd4a68">callOtherDomain</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
<span style="color:#0077aa">if</span><span style="color:#999999">(</span>invocation<span style="color:#999999">)</span> <span style="color:#999999">{</span>
invocation<span style="color:#999999">.</span><span style="color:#dd4a68">open</span><span style="color:#999999">(</span><span style="color:#669900">'GET'</span><span style="color:#999999">,</span> url<span style="color:#999999">,</span> <span style="color:#990055">true</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
invocation<span style="color:#999999">.</span>onreadystatechange <span style="color:#9a6e3a">=</span> handler<span style="color:#999999">;</span>
invocation<span style="color:#999999">.</span><span style="color:#dd4a68">send</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>
用戶端和伺服器之間使用 CORS 首部字段來處理權限:
分别檢視請求封包和響應封包:
<span style="color:#333333"><code class="language-shell">GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 <span style="color:#999999">(</span>Macintosh<span style="color:#999999">;</span> U<span style="color:#999999">;</span> Intel Mac OS X <span style="color:#990055">10.5</span><span style="color:#999999">;</span> en-US<span style="color:#999999">;</span> rv:1.9.1b3pre<span style="color:#999999">)</span> Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml<span style="color:#999999">;</span><span style="color:#ee9900">q</span><span style="color:#9a6e3a">=</span><span style="color:#990055">0.9</span>,*/*<span style="color:#999999">;</span><span style="color:#ee9900">q</span><span style="color:#9a6e3a">=</span><span style="color:#990055">0.8</span>
Accept-Language: en-us,en<span style="color:#999999">;</span><span style="color:#ee9900">q</span><span style="color:#9a6e3a">=</span><span style="color:#990055">0.5</span>
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8<span style="color:#999999">;</span><span style="color:#ee9900">q</span><span style="color:#9a6e3a">=</span><span style="color:#990055">0.7</span>,*<span style="color:#999999">;</span><span style="color:#ee9900">q</span><span style="color:#9a6e3a">=</span><span style="color:#990055">0.7</span>
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example
HTTP/1.1 <span style="color:#990055">200</span> OK
Date: Mon, 01 Dec <span style="color:#990055">2008</span> 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: <span style="color:#ee9900">timeout</span><span style="color:#9a6e3a">=</span><span style="color:#990055">2</span>, <span style="color:#ee9900">max</span><span style="color:#9a6e3a">=</span><span style="color:#990055">100</span>
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
<span style="color:#999999">[</span>XML Data<span style="color:#999999">]</span>
</code></span>
第 1~10 行是請求首部。第10行 的請求首部字段 Origin 表明該請求來源于
http://foo.example
。
第 13~22 行是來自于 http://bar.other 的服務端響應。響應中攜帶了響應首部字段 Access-Control-Allow-Origin(第 16 行)。使用 Origin 和 Access-Control-Allow-Origin 就能完成最簡單的通路控制。本例中,服務端傳回的
Access-Control-Allow-Origin: *
表明,該資源可以被任意外域通路。如果服務端僅允許來自 http://foo.example 的通路,該首部字段的内容如下:
Access-Control-Allow-Origin: http://foo.example
現在,除了 http://foo.example,其它外域均不能通路該資源(該政策由請求首部中的 ORIGIN 字段定義,見第10行)。
Access-Control-Allow-Origin
應當為 * 或者包含由 Origin 首部字段所指明的域名。
預檢請求
與前述簡單請求不同,“需預檢的請求”要求必須首先使用 OPTIONS 方法發起一個預檢請求到伺服器,以獲知伺服器是否允許該實際請求。"預檢請求“的使用,可以避免跨域請求對伺服器的使用者資料産生未預期的影響。
如下是一個需要執行預檢請求的 HTTP 請求:
<span style="color:#333333"><code class="language-js"><span style="color:#0077aa">var</span> invocation <span style="color:#9a6e3a">=</span> <span style="color:#0077aa">new</span> <span style="color:#dd4a68">XMLHttpRequest</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#0077aa">var</span> url <span style="color:#9a6e3a">=</span> <span style="color:#669900">'http://bar.other/resources/post-here/'</span><span style="color:#999999">;</span>
<span style="color:#0077aa">var</span> body <span style="color:#9a6e3a">=</span> <span style="color:#669900">'<?xml version="1.0"?><person><name>Arun</name></person>'</span><span style="color:#999999">;</span>
<span style="color:#0077aa">function</span> <span style="color:#dd4a68">callOtherDomain</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
<span style="color:#0077aa">if</span><span style="color:#999999">(</span>invocation<span style="color:#999999">)</span>
<span style="color:#999999">{</span>
invocation<span style="color:#999999">.</span><span style="color:#dd4a68">open</span><span style="color:#999999">(</span><span style="color:#669900">'POST'</span><span style="color:#999999">,</span> url<span style="color:#999999">,</span> <span style="color:#990055">true</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
invocation<span style="color:#999999">.</span><span style="color:#dd4a68">setRequestHeader</span><span style="color:#999999">(</span><span style="color:#669900">'X-PINGOTHER'</span><span style="color:#999999">,</span> <span style="color:#669900">'pingpong'</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
invocation<span style="color:#999999">.</span><span style="color:#dd4a68">setRequestHeader</span><span style="color:#999999">(</span><span style="color:#669900">'Content-Type'</span><span style="color:#999999">,</span> <span style="color:#669900">'application/xml'</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
invocation<span style="color:#999999">.</span>onreadystatechange <span style="color:#9a6e3a">=</span> handler<span style="color:#999999">;</span>
invocation<span style="color:#999999">.</span><span style="color:#dd4a68">send</span><span style="color:#999999">(</span>body<span style="color:#999999">)</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
<span style="color:#999999">}</span>
<span style="color:#9a6e3a">...</span><span style="color:#9a6e3a">...</span>
</code></span>
上面的代碼使用 POST 請求發送一個 XML 文檔,該請求包含了一個自定義的請求首部字段(X-PINGOTHER: pingpong)。另外,該請求的 Content-Type 為 application/xml。是以,該請求需要首先發起“預檢請求”。
<span style="color:#333333"><code class="language-html">OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain</code></span>
預檢請求完成之後,發送實際請求:
<span style="color:#333333"><code>POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache
Cache-Control: no-cache
<?xml version="1.0"?><person><name>Arun</name></person>
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain
[Some GZIP'd payload]</code></span>
浏覽器檢測到,從 JavaScript 中發起的請求需要被預檢。從上面的封包中,我們看到,第 1~12 行發送了一個使用
OPTIONS 方法的“
預檢請求
”。
OPTIONS 是 HTTP/1.1 協定中定義的方法,用以從伺服器擷取更多資訊。該方法不會對伺服器資源産生影響。 預檢請求中同時攜帶了下面兩個首部字段:
<span style="color:#333333"><code>Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type</code></span>
首部字段 Access-Control-Request-Method 告知伺服器,實際請求将使用 POST 方法。首部字段 Access-Control-Request-Headers 告知伺服器,實際請求将攜帶兩個自定義請求首部字段:
X-PINGOTHER
與
Content-Type
。伺服器據此決定,該實際請求是否被允許。
第14~26 行為預檢請求的響應,表明伺服器将接受後續的實際請求。重點看第 17~20 行:
<span style="color:#333333"><code>Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400</code></span>
首部字段
Access-Control-Allow-Methods
表明伺服器允許用戶端使用
POST,
GET
和
OPTIONS
方法發起請求。該字段與 HTTP/1.1 Allow: response header 類似,但僅限于在需要通路控制的場景中使用。
首部字段
Access-Control-Allow-Headers
表明伺服器允許請求中攜帶字段
X-PINGOTHER
與
Content-Type
。與
Access-Control-Allow-Methods
一樣,
Access-Control-Allow-Headers
的值為逗号分割的清單。
最後,首部字段
Access-Control-Max-Age
表明該響應的有效時間為 86400 秒,也就是 24 小時。在有效時間内,浏覽器無須為同一請求再次發起預檢請求。請注意,浏覽器自身維護了一個最大有效時間,如果該首部字段的值超過了最大有效時間,将不會生效。
預檢請求與重定向
大多數浏覽器不支援針對于預檢請求的重定向。如果一個預檢請求發生了重定向,浏覽器将報告錯誤:
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
Request requires preflight, which is disallowed to follow cross-origin redirect
CORS 最初要求該行為,不過在後續的修訂中廢棄了這一要求。
在浏覽器的實作跟上規範之前,有兩種方式規避上述報錯行為:
- 在服務端去掉對預檢請求的重定向;
- 将實際請求變成一個簡單請求。
如果上面兩種方式難以做到,我們仍有其他辦法:
- 發出一個簡單請求(使用 Response.url 或 XHR.responseURL)以判斷真正的預檢請求會傳回什麼位址。
- 發出另一個請求(真正的請求),使用在上一步通過Response.url 或 XMLHttpRequest.responseURL獲得的URL。
不過,如果請求是由于存在 Authorization 字段而引發了預檢請求,則這一方法将無法使用。這種情況隻能由服務端進行更改。
附帶身份憑證的請求
XMLHttpRequest 或 Fetch 與 CORS 的一個有趣的特性是,可以基于 HTTP cookies 和 HTTP 認證資訊發送身份憑證。一般而言,對于跨源 XMLHttpRequest 或 Fetch 請求,浏覽器不會發送身份憑證資訊。如果要發送憑證資訊,需要設定
XMLHttpRequest
的某個特殊标志位。
本例中,http://foo.example 的某腳本向 http://bar.other 發起一個GET 請求,并設定 Cookies:
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain(){
if(invocation) {
invocation.open('GET', url, true);
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
}
第 7 行将
XMLHttpRequest
的
withCredentials
标志設定為
true
,進而向伺服器發送 Cookies。因為這是一個簡單 GET 請求,是以浏覽器不會對其發起“預檢請求”。但是,如果伺服器端的響應中未攜帶
Access-Control-Allow-Credentials: true
,浏覽器将不會把響應内容傳回給請求的發送者。
用戶端與伺服器端互動示例如下:
<span style="color:#333333"><code>GET /resources/access-control-with-credentials/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Referer: http://foo.example/examples/credential.html
Origin: http://foo.example
Cookie: pageAccess=2
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
[text/plain payload]</code></span>
即使第 10 行指定了 Cookie 的相關資訊,但是,如果 bar.other 的響應中缺失 Access-Control-Allow-Credentials
: true
(第 17 行),則響應内容不會傳回給請求的發起者。
附帶身份憑證的請求與通配符
對于附帶身份憑證的請求,伺服器不得設定
Access-Control-Allow-Origin
的值為“
*
”。
這是因為請求的首部中攜帶了
Cookie
資訊,如果
Access-Control-Allow-Origin
的值為“
*
”,請求将會失敗。而将
Access-Control-Allow-Origin
的值設定為
http://foo.example
,則請求将成功執行。
另外,響應首部中也攜帶了 Set-Cookie 字段,嘗試對 Cookie 進行修改。如果操作失敗,将會抛出異常。
第三方 cookies
注意在 CORS 響應中設定的 cookies 适用一般性第三方 cookie 政策。在上面的例子中,頁面是在 `foo.example` 加載,但是第 20 行的 cookie 是被 `bar.other` 發送的,如果使用者設定其浏覽器拒絕所有第三方 cookies,那麼将不會被儲存。
HTTP 響應首部字段
本節列出了規範所定義的響應首部字段。上一小節中,我們已經看到了這些首部字段在實際場景中是如何工作的。
Access-Control-Allow-Origin
響應首部中可以攜帶一個 Access-Control-Allow-Origin 字段,其文法如下:
<span style="color:#333333"><code class="language-html">Access-Control-Allow-Origin: <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>origin</span><span style="color:#999999">></span></span> | *
</code></span>
其中,origin 參數的值指定了允許通路該資源的外域 URI。對于不需要攜帶身份憑證的請求,伺服器可以指定該字段的值為通配符,表示允許來自所有域的請求。
例如,下面的字段值将允許來自 http://mozilla.com 的請求:
<span style="color:#333333">Access-Control-Allow-Origin: http://mozilla.com</span>
如果服務端指定了具體的域名而非“*”,那麼響應首部中的 Vary 字段的值必須包含 Origin。這将告訴用戶端:伺服器對不同的源站傳回不同的内容。
Access-Control-Expose-Headers
譯者注:在跨源通路時,XMLHttpRequest對象的getResponseHeader()方法隻能拿到一些最基本的響應頭,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要通路其他頭,則需要伺服器設定本響應頭。
Access-Control-Expose-Headers 頭讓伺服器把允許浏覽器通路的頭放入白名單,例如:
<span style="color:#333333"><code class="language-html">Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
</code></span>
這樣浏覽器就能夠通過getResponseHeader通路
X-My-Custom-Header
和
X-Another-Custom-Header
響應頭了。
Access-Control-Max-Age
Access-Control-Max-Age 頭指定了preflight請求的結果能夠被緩存多久,請參考本文在前面提到的preflight例子。
<span style="color:#333333"><code class="language-html">Access-Control-Max-Age: <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>delta-seconds</span><span style="color:#999999">></span></span>
</code></span>
delta-seconds
參數表示preflight請求的結果在多少秒内有效。
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials 頭指定了當浏覽器的
credentials
設定為true時是否允許浏覽器讀取response的内容。當用在對preflight預檢測請求的響應中時,它指定了實際的請求是否可以使用
credentials
。請注意:簡單 GET 請求不會被預檢;如果對此類請求的響應中不包含該字段,這個響應将被忽略掉,并且浏覽器也不會将相應内容傳回給網頁。
<span style="color:#333333"><code class="language-html">Access-Control-Allow-Credentials: true
</code></span>
上文已經讨論了附帶身份憑證的請求。
Access-Control-Allow-Methods
Access-Control-Allow-Methods 首部字段用于預檢請求的響應。其指明了實際請求所允許使用的 HTTP 方法。
<span style="color:#333333"><code class="language-html">Access-Control-Allow-Methods: <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>method</span><span style="color:#999999">></span></span>[, <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>method</span><span style="color:#999999">></span></span>]*
</code></span>
相關示例見這裡。
Access-Control-Allow-Headers
Access-Control-Allow-Headers 首部字段用于預檢請求的響應。其指明了實際請求中允許攜帶的首部字段。
<span style="color:#333333"><code class="language-html">Access-Control-Allow-Headers: <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>field-name</span><span style="color:#999999">></span></span>[, <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>field-name</span><span style="color:#999999">></span></span>]*
</code></span>
HTTP 請求首部字段
本節列出了可用于發起跨源請求的首部字段。請注意,這些首部字段無須手動設定。 當開發者使用 XMLHttpRequest 對象發起跨源請求時,它們已經被設定就緒。
Origin
Origin 首部字段表明預檢請求或實際請求的源站。
<span style="color:#333333"><code class="language-html">Origin: <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>origin</span><span style="color:#999999">></span></span>
</code></span>
origin 參數的值為源站 URI。它不包含任何路徑資訊,隻是伺服器名稱。
Note: 有時候将該字段的值設定為空字元串是有用的,例如,當源站是一個 data URL 時。
注意,在所有通路控制請求(Access control request)中,Origin 首部字段總是被發送。
Access-Control-Request-Method
Access-Control-Request-Method 首部字段用于預檢請求。其作用是,将實際請求所使用的 HTTP 方法告訴伺服器。
<span style="color:#333333"><code class="language-html">Access-Control-Request-Method: <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>method</span><span style="color:#999999">></span></span>
</code></span>
相關示例見這裡。
Access-Control-Request-Headers
Access-Control-Request-Headers 首部字段用于預檢請求。其作用是,将實際請求所攜帶的首部字段告訴伺服器。
<span style="color:#333333"><code class="language-html">Access-Control-Request-Headers: <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>field-name</span><span style="color:#999999">></span></span>[, <span style="color:#990055"><span style="color:#990055"><span style="color:#999999"><</span>field-name</span><span style="color:#999999">></span></span>]*
</code></span>
相關示例見這裡。
規範
Specification | Status | Comment |
Fetch CORS | Living Standard | New definition; supplants CORS specification. |
Unknown | Unknown | Initial definition. |
浏覽器相容性
Update compatibility data on GitHub
Desktop | Mobile | |||||||||||
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | Android webview | Chrome for Android | Firefox for Android | Opera for Android | Safari on iOS | Samsung Internet | |
Access-Control-Allow-Origin | Full support4 | Full support12 | Full support3.5 | Full support10 | Full support12 | Full support4 | Full support2 | Full supportYes | Full support4 | Full support12 | Full support3.2 | Full supportYes |
What are we missing?
Legend
注
- IE 10 提供了對規範的完整支援,但在較早版本(8 和 9)中,CORS 機制是借由 XDomainRequest 對象完成的。
- Firefox 3.5 引入了對 XMLHttpRequests 和 Web 字型的跨源支援(但最初的實作并不完整,這在後續版本中得到完善);Firefox 7 引入了對 WebGL 貼圖的跨源支援;Firefox 9 引入了對 drawImage 的跨源支援。
參見
- Code Samples Showing XMLHttpRequest
- Cross-Origin Resource Sharing From a Server-Side Perspective (PHP, etc.)
- Cross-Origin Resource Sharing specification
- XMLHttpRequest
- Fetch API
- Using CORS with All (Modern) Browsers
- Using CORS - HTML5 Rocks