CORS是一個(gè)W3C標(biāo)準(zhǔn)
它允許瀏覽器向跨域服務(wù)器發(fā)送XMLHttpRequest請(qǐng)求,從而克服ajax只能發(fā)送同源請(qǐng)求的限制
簡(jiǎn)介
CORS需要瀏覽器和服務(wù)器同時(shí)支持剑勾。目前瀏覽器都支持庇楞,IE10以上才支持
整個(gè)CORS通信過程,都是瀏覽器自行完成,無需用戶參與猪落,整個(gè)代碼與ajax發(fā)送同源請(qǐng)求沒有區(qū)別,在發(fā)送過程中畴博,瀏覽器檢測(cè)到是ajax跨域笨忌,就會(huì)自動(dòng)添加一些頭信息
CORS請(qǐng)求的關(guān)鍵是服務(wù)器,只要服務(wù)器實(shí)現(xiàn)了CORS請(qǐng)求接口俱病,即可實(shí)現(xiàn)CORS
兩種請(qǐng)求
瀏覽器將CORS請(qǐng)求分為兩類:簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求官疲,對(duì)于這兩者的處理是不一樣的
凡是滿足一下條件的就是簡(jiǎn)單請(qǐng)求:
請(qǐng)求方法是以下三個(gè)請(qǐng)求之一:
- HEAD
- GET
- POST
HTTP的頭信息不超出以下幾種字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type只限于這三個(gè)值:
application/x-www-form-urlencoded、multipart/form-data亮隙、text/plain
凡是不同時(shí)滿足上面兩個(gè)請(qǐng)求的途凫,都屬于非簡(jiǎn)單請(qǐng)求
簡(jiǎn)單請(qǐng)求
對(duì)于簡(jiǎn)單請(qǐng)求,瀏覽器直接發(fā)出CORS請(qǐng)求溢吻,也就是在請(qǐng)求頭信息中添加origin字段
上面圖中的oringin字段用來說明维费,本次請(qǐng)求來自哪個(gè)源(協(xié)議+域名+端口),服務(wù)器根據(jù)這些信息來決定是否響應(yīng)請(qǐng)求
如果Origin指定的源促王,不在服務(wù)器的許可范圍之類犀盟,服務(wù)器會(huì)返回一個(gè)正常的HTTP回應(yīng),瀏覽器接收到回應(yīng)后蝇狼,發(fā)現(xiàn)頭信息里沒有包含Access-Control-Allow-Origin
字段阅畴,就知道出錯(cuò)了,從而拋出一個(gè)錯(cuò)誤题翰,被XMLHttpRequest的onerror
回調(diào)函數(shù)捕獲恶阴。
注意:這種錯(cuò)誤不能通過狀態(tài)碼識(shí)別诈胜,因?yàn)镠TTP回應(yīng)的狀態(tài)碼很可能是200
。
如果Origin指定的源在許可范圍之內(nèi)冯事,瀏覽器返回的響應(yīng)中會(huì)包含以下頭信息:
以上的頭信息中包含焦匈,有三個(gè)與
CORS
請(qǐng)求相關(guān)的字段,都以Access-Control-
開頭
- Access-Control-Allow-Origin
該字段是必須的昵仅,它的值要么與瀏覽器發(fā)送的Origin
的值相同缓熟,要么為*
,表示接受任意域名的請(qǐng)求
- Access-Control-Allow-Credentials
該字段可選摔笤。它的值是一個(gè)布爾值够滑,表示是否允許發(fā)送Cookie。默認(rèn)情況下吕世,Cookie不包括在CORS請(qǐng)求之中彰触。設(shè)為true,即表示服務(wù)器明確許可命辖,Cookie可以包含在請(qǐng)求中况毅,一起發(fā)給服務(wù)器。這個(gè)值也只能設(shè)為true尔艇,如果服務(wù)器不要瀏覽器發(fā)送Cookie尔许,刪除該字段即可。
- Access-Control-Expose-Headers
該字段可選终娃。CORS請(qǐng)求時(shí)味廊,XMLHttpRequest對(duì)象的getResponseHeader()方法只能拿到6個(gè)基本字段:Cache-Control、Content-Language棠耕、Content-Type余佛、Expires、Last-Modified窍荧、Pragma衙熔。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定搅荞。上面的例子指定红氯,getResponseHeader('FooBar')可以返回FooBar字段的值。
非簡(jiǎn)單請(qǐng)求
非簡(jiǎn)單請(qǐng)求就是指那些對(duì)服務(wù)器有特殊要求的請(qǐng)求咕痛,比如請(qǐng)求方法是PUT
或DELETE
痢甘,或者Content-Type字段的類型是application/json。
非簡(jiǎn)單請(qǐng)求的CORS請(qǐng)求茉贡,會(huì)在正式通信之前塞栅,增加一次HTTP查詢請(qǐng)求,稱為"預(yù)檢"請(qǐng)求(preflight)腔丧,請(qǐng)求方法是Options放椰,如果服務(wù)器允許此次跨域請(qǐng)求作烟,則會(huì)將相應(yīng)的信息添加到Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Max-Age
等字段中,并返回給瀏覽器砾医,瀏覽器接收到這些信息后拿撩,再發(fā)送真實(shí)的請(qǐng)求。
預(yù)撿的作用是:判斷當(dāng)前域名是否在服務(wù)器的許可名單之中如蚜,以及方法和頭信息是否允許使用压恒,只有這些條件都達(dá)成之后,服務(wù)器才會(huì)在響應(yīng)報(bào)文中添加帶有Access-Control-Allow-
頭信息的字段错邦,瀏覽器接收到響應(yīng)后探赫,才會(huì)發(fā)送真實(shí)的請(qǐng)求。
預(yù)檢請(qǐng)求如下:
1.OPTIONS /resources/post-here/ HTTP/1.1
2.Host: bar.other
3.User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
4.Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
5.Accept-Language: en-us,en;q=0.5
6.Accept-Encoding: gzip,deflate
7.Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
8.Connection: keep-alive
9.Origin: http://foo.example
10.Access-Control-Request-Method: POST
11.Access-Control-Request-Headers: X-PINGOTHER, Content-Type
12.
13.
14.HTTP/1.1 200 OK
15.Date: Mon, 01 Dec 2008 01:15:39 GMT
16.Server: Apache/2.0.61 (Unix)
17.Access-Control-Allow-Origin: http://foo.example
18.Access-Control-Allow-Methods: POST, GET, OPTIONS
19.Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
20.Access-Control-Max-Age: 86400
21.Vary: Accept-Encoding, Origin
22.Content-Encoding: gzip
23.Content-Length: 0
24.Keep-Alive: timeout=2, max=100
25.Connection: Keep-Alive
26.Content-Type: text/plain
預(yù)檢完成之后的實(shí)際請(qǐng)求如下:
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]
與JSONP的比較
CORS與JSONP的使用目的相同撬呢,但是比JSONP更強(qiáng)大伦吠。
JSONP只支持GET請(qǐng)求,CORS支持所有類型的HTTP請(qǐng)求魂拦。
JSONP的優(yōu)勢(shì)在于支持老式瀏覽器讨勤,以及可以向不支持CORS的網(wǎng)站請(qǐng)求數(shù)據(jù)。
參考: 跨域資源共享 CORS 詳解