概述
出于安全原因激才,瀏覽器允許通過(guò)標(biāo)簽進(jìn)行跨域訪問(wèn)(如img標(biāo)簽的src屬性)朗若,但
限制從腳本內(nèi)發(fā)起的跨源訪問(wèn)(如Ajax)署海。
為了統(tǒng)一解決瀏覽器中腳本內(nèi)跨域請(qǐng)求問(wèn)題(如Ajax)枯跑,W3C于2014年發(fā)布CORS(Cross-Origin Resource Sharing亭枷,跨域資源共享)標(biāo)準(zhǔn)。
此方案需要瀏覽器和服務(wù)端同時(shí)支持掏熬。
目前所有現(xiàn)代瀏覽器都支持此標(biāo)準(zhǔn)佑稠。
原理
W3C新增以下HTTP頭字段,讓服務(wù)端聲明哪些網(wǎng)站有哪些權(quán)限訪問(wèn)服務(wù)端哪些資源孽江。
請(qǐng)求頭:
Origin(必選)
參數(shù)的值為請(qǐng)求跨域資源的 URI讶坯。不包含任何路徑信息,只是服務(wù)器名稱(chēng)岗屏,一般格式為:scheme://host [:port]
,如http://192.168.1.100:80Access-Control-Request-Method
用于預(yù)檢請(qǐng)求辆琅。其作用是漱办,將實(shí)際請(qǐng)求所使用的 HTTP 方法告訴服務(wù)器。Access-Control-Request-Headers
用于預(yù)檢請(qǐng)求婉烟。其作用是娩井,將實(shí)際請(qǐng)求所攜帶的頭字段告訴服務(wù)器。
逗號(hào)分割似袁。
應(yīng)答頭:
- Access-Control-Allow-Origin:<origin> | *
指定允許訪問(wèn)該資源的外域 URI洞辣。
<origin>=僅允許此源進(jìn)行訪問(wèn),可以暴露身份憑證
* =允許任意URI訪問(wèn),但不允許暴露身份憑證
Access-Control-Allow-Credentials:true
指定了當(dāng)瀏覽器的credentials設(shè)置為true時(shí)是否允許瀏覽器讀取response的內(nèi)容昙衅。如果不允許扬霜,則不添加此字段。Access-Control-Expose-Headers
允許暴露的應(yīng)答頭而涉,用逗號(hào)分割著瓶。未暴露的頭,不允許腳本訪問(wèn)啼县。Access-Control-Max-Age:單位s
用于預(yù)檢請(qǐng)求的響應(yīng)材原。指定了預(yù)檢(preflight)請(qǐng)求的結(jié)果能夠被使用多久。Access-Control-Allow-Methods
用于預(yù)檢請(qǐng)求的響應(yīng)季眷。其指明了實(shí)際請(qǐng)求所允許使用的 HTTP 方法余蟹。
逗號(hào)分割。Access-Control-Allow-Headers
用于預(yù)檢請(qǐng)求的響應(yīng)子刮。其指明了實(shí)際請(qǐng)求中允許攜帶的頭字段威酒。
逗號(hào)分割。
兩類(lèi)請(qǐng)求
另規(guī)定瀏覽器把跨域請(qǐng)求分為兩類(lèi)且對(duì)應(yīng)不同的處理方式:
簡(jiǎn)單請(qǐng)求(simple request)
請(qǐng)求方法為HEAD/GET/POST且請(qǐng)求頭僅為下面幾種:
Accept
Accept-Language
Content-Language
Content-Type:僅能是下面三種之一
application/x-www-form-urlencoded
multipart/form-data
text/plain
DPR:任意
Downlink:任意
Save-Data:任意
Viewport-Width:任意
Width:任意
非簡(jiǎn)單請(qǐng)求(not-so-simple request)
對(duì)于非簡(jiǎn)單請(qǐng)求瀏覽器必須首先使用 OPTIONS 方法發(fā)起一個(gè)預(yù)檢請(qǐng)求(preflight request)挺峡,從而獲知服務(wù)端是否允許該跨域請(qǐng)求兼搏。
服務(wù)器確認(rèn)允許之后,才發(fā)起實(shí)際的 HTTP 請(qǐng)求沙郭。
Ajax跨域處理步驟
簡(jiǎn)單請(qǐng)求
客戶(hù)端:
如果需要發(fā)送cookie和認(rèn)證信息,則設(shè)置XMLHttpRequest對(duì)象的withCredentials屬性為true裳朋,如:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
服務(wù)端:
設(shè)置下面對(duì)應(yīng)應(yīng)答頭即可病线。
- (必選)Access-Control-Allow-Origin應(yīng)答頭為請(qǐng)求源或*(但如果需要返回cookie和認(rèn)證信息,則不能設(shè)置為*)
- (可選) Access-Control-Allow-Credentials設(shè)置為true鲤嫡,用于暴露cookie和認(rèn)證信息送挑。
- (可選) Access-Control-Expose-Headers設(shè)置為需要暴露的應(yīng)答頭。
非簡(jiǎn)單請(qǐng)求
由瀏覽器判斷一個(gè)請(qǐng)求是簡(jiǎn)單請(qǐng)求還是非簡(jiǎn)單請(qǐng)求暖眼。即客戶(hù)端Ajax不需要做什么處理惕耕。
服務(wù)端:
需要編寫(xiě)一個(gè)能夠處理Option預(yù)檢請(qǐng)求的Servlet,然后返回實(shí)際允許的請(qǐng)求方法诫肠,請(qǐng)求頭和有效時(shí)間司澎。
- Access-Control-Max-Age:單位s
指定了預(yù)檢(preflight)請(qǐng)求的結(jié)果能夠被使用多久欺缘。即在此時(shí)間內(nèi)容,瀏覽器不用再次發(fā)送預(yù)檢請(qǐng)求挤安。 - Access-Control-Allow-Methods
用于預(yù)檢請(qǐng)求的響應(yīng)谚殊。其指明了實(shí)際請(qǐng)求所允許使用的 HTTP 方法。
逗號(hào)分割蛤铜。 - Access-Control-Allow-Headers
用于預(yù)檢請(qǐng)求的響應(yīng)嫩絮。其指明了實(shí)際請(qǐng)求中允許攜帶的頭字段。
逗號(hào)分割围肥。