瀏覽器默認(rèn)是不允許XMLHttpRequest(ajax)發(fā)送請(qǐng)求到其他網(wǎng)站(跨域)的,
比如a網(wǎng)站的javascript想要從b網(wǎng)站獲取數(shù)據(jù)時(shí)就會(huì)被瀏覽器攔截。這也是為了安全考慮,如果不做限制的話(huà),
a網(wǎng)站的js 請(qǐng)求b網(wǎng)站時(shí)默認(rèn)會(huì)把b網(wǎng)站的cookie帶上,a網(wǎng)站就可以以b網(wǎng)站的登錄信息(b網(wǎng)站的cookie)去攻擊b網(wǎng)站。
但是實(shí)際應(yīng)用中,有時(shí)候確實(shí)需要跨域請(qǐng)求的,跨源資源共享 (CORS)就是用來(lái)解決實(shí)現(xiàn)這種功能的。
CORS是http協(xié)議的一部分,需要瀏覽器和web服務(wù)器共同支持,目前絕大多數(shù)的瀏覽器和服務(wù)器都已支持。
CORS把請(qǐng)求分成兩類(lèi),簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求
簡(jiǎn)單請(qǐng)求:
同時(shí)滿(mǎn)足下面兩個(gè)條件就是簡(jiǎn)單請(qǐng)求
(1) 請(qǐng)求方法是以下三種方法之一:
HEAD
GET
POST
(2)HTTP的頭信息不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data、text/plain

簡(jiǎn)單請(qǐng)求過(guò)程如上圖,步驟為:
1.瀏覽器發(fā)現(xiàn)ajax的請(qǐng)求時(shí)跨域的,會(huì)在請(qǐng)求頭里面添加一個(gè)origin字段,值為當(dāng)前域地址(不包含路徑)。
2.服務(wù)器拿到請(qǐng)求后會(huì)正常處理請(qǐng)求,然后再檢查請(qǐng)求的頭,發(fā)現(xiàn)origin,就知道這是跨域的請(qǐng)求,會(huì)檢查origin的域名是否在服務(wù)器的許可列表里,如國(guó)在就在響應(yīng)頭添加一個(gè)Access-Control-Allow-Origin字段,值就是origin的值。如果不在就不設(shè)置Access-Control-Allow-Origin這個(gè)頭。然后返回相應(yīng)
3.瀏覽器收到響應(yīng),知道這是個(gè)跨域的響應(yīng),檢查響應(yīng)頭里是否有Access-Control-Allow-Origin,如果沒(méi)有就立即報(bào)錯(cuò)并停止執(zhí)行ajax的代碼,如果有,并且值為自己的域名,或者為通配符*,就正常處理。
注意在這種簡(jiǎn)單請(qǐng)求里,瀏覽器會(huì)正常發(fā)送請(qǐng)求的,服務(wù)器也會(huì)正常處理請(qǐng)求,唯一可能被攔截的就是最后瀏覽器收到響應(yīng)后是否會(huì)處理,如果沒(méi)有Access-Control-Allow-Origin這個(gè)頭信息,就會(huì)停止處理。所以這個(gè)過(guò)程請(qǐng)求響應(yīng)一定還是會(huì)被處理的。
非簡(jiǎn)單請(qǐng)求
如果請(qǐng)求不符合簡(jiǎn)單請(qǐng)求的條件,就是非簡(jiǎn)單請(qǐng)求。這種請(qǐng)求一般會(huì)修改服務(wù)器上的資源,所以處理上比較嚴(yán)格。

非簡(jiǎn)單請(qǐng)求過(guò)程如上圖,步驟為:
- 瀏覽器發(fā)現(xiàn)ajax的請(qǐng)求是跨域的,并且是非簡(jiǎn)單請(qǐng)求,為了服務(wù)器的安全,不會(huì)像簡(jiǎn)單請(qǐng)求一樣直接發(fā)送請(qǐng)求,而是會(huì)先發(fā)送一個(gè)OPTIONS的請(qǐng)求給服務(wù)器,詢(xún)問(wèn)服務(wù)器網(wǎng)頁(yè)所在的域名是否在服務(wù)器的許可名單之中,以及可以使用哪些HTTP動(dòng)詞和頭信息字段。只有得到肯定答復(fù),瀏覽器才會(huì)發(fā)出正式的XMLHttpRequest請(qǐng)求,否則就報(bào)錯(cuò),這個(gè)請(qǐng)求里也會(huì)有origin頭信息。
2.服務(wù)器收到"預(yù)檢"請(qǐng)求以后,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,確認(rèn)允許跨源請(qǐng)求,就可以做出回應(yīng)
3.瀏覽器收到服務(wù)器的“預(yù)檢請(qǐng)求”響應(yīng)后,檢查頭信息里的Access-Control-Allow-Origin字段,如果為當(dāng)前的域名或者為通配符*, 則知道這個(gè)跨域請(qǐng)求可以進(jìn)行,就會(huì)正常發(fā)送用戶(hù)的請(qǐng)求,否則為不可進(jìn)行,攔截用戶(hù)的請(qǐng)求
從上面的過(guò)程可以看到,無(wú)論是簡(jiǎn)單還是非簡(jiǎn)單請(qǐng)求,CORS的過(guò)程都需要服務(wù)端和瀏覽器共同配合,
請(qǐng)求只要通過(guò)了瀏覽器的驗(yàn)證,服務(wù)器總是會(huì)正常處理。所以如果我們使用代碼怕蟲(chóng)來(lái)發(fā)送請(qǐng)求,就不會(huì)有跨域請(qǐng)求的問(wèn)題,總能成功。
另外注意到,簡(jiǎn)單請(qǐng)求服務(wù)器總是會(huì)處理,攔截只發(fā)生在瀏覽器處理服務(wù)器響應(yīng)過(guò)程中,在chrome的network里還是可以看到服務(wù)器返回的正常數(shù)據(jù),并且響應(yīng)碼200正常。這就警示我們,不要在簡(jiǎn)單類(lèi)型的請(qǐng)求里更新重要數(shù)據(jù),否則跨站cookie攻擊漏洞就會(huì)發(fā)生。