受瀏覽器的同源策略限制公壤,JavaSript只能請求本域內(nèi)的資源∨烀剑跨域資源共享(Cross-Origin Resource Sharing, CORS)是為解決Ajax技術(shù)難實現(xiàn)跨域問題而提出的一個規(guī)范后雷,這個規(guī)范試著從根本上解決安全的跨域資源共享問題。在此之前鼓鲁,解決此類問題的途徑往往是服務(wù)器代理、JSONP等仔沿,治標(biāo)不治本坐桩。目前基本所有瀏覽器都已經(jīng)支持該規(guī)范。
一個域是由schema封锉、host、port三者共同組成膘螟,與路徑無關(guān)成福。所謂跨域,是指在http://example-foo.com/域上通
過XMLHttpRequest對象調(diào)用http://example-bar.com/域上的資源荆残。CORS約定服務(wù)器端和瀏覽器在HTTP協(xié)議之上奴艾,通過一些額外HTTP頭部信息,進(jìn)行跨域資源共享的協(xié)商内斯。服務(wù)器端和瀏覽器都必需遵循規(guī)范中的要求蕴潦。
CORS把HTTP請求分成兩類,不同類別按不同的策略進(jìn)行跨域資源共享協(xié)商俘闯。
注意:現(xiàn)代手機(jī)瀏覽器都支持跨域潭苞,跨域訪問不拒絕大都是pc瀏覽器造成!
- 簡單跨域請求真朗。當(dāng)HTTP請求出現(xiàn)以下兩種情況時此疹,瀏覽器認(rèn)為是簡單跨域請求:
1). 請求方法是GET、HEAD或者POST,并且當(dāng)請求方法是POST時蝗碎,Content-Type必須是application/x-www-form-urlencoded, multipart/form-data或著text/plain中的一個值湖笨。2). 請求中沒有自定義HTTP頭部。
對于簡單跨域請求蹦骑,瀏覽器要做的就是在HTTP請求中添加Origin Header慈省,將JavaScript腳本所在域填充進(jìn)去,向其他域的服務(wù)器請求資源眠菇。服務(wù)器端收到一個簡單跨域請求后辫呻,根據(jù)資源權(quán)限配置,在響應(yīng)頭中添加Access-Control-Allow-Origin Header琼锋。瀏覽器收到響應(yīng)后放闺,查看Access-Control-Allow-Origin Header,如果當(dāng)前域已經(jīng)得到授權(quán)缕坎,則將結(jié)果返回給JavaScript怖侦。否則瀏覽器忽略此次響應(yīng)。 - 帶預(yù)檢(Preflighted)的跨域請求谜叹。當(dāng)HTTP請求出現(xiàn)以下兩種情況時匾寝,瀏覽器認(rèn)為是帶預(yù)檢(Preflighted)的跨域請求:
1). 除GET、HEAD和POST(only with application/x-www-form-urlencoded, multipart/form-data, text/plain Content-Type)以外的其他HTTP方法荷腊。2). 請求中出現(xiàn)自定義HTTP頭部艳悔。
帶預(yù)檢(Preflighted)的跨域請求需要瀏覽器在發(fā)送真實HTTP請求之前先發(fā)送一個OPTIONS的預(yù)檢請求,檢測服務(wù)器端是否支持真實請求進(jìn)行跨域資源訪問女仰,真實請求的信息在OPTIONS請求中通過Access-Control-Request-Method Header和Access-Control-Request-Headers Header描述猜年,此外與簡單跨域請求一樣,瀏覽器也會添加Origin Header疾忍。服務(wù)器端接到預(yù)檢請求后乔外,根據(jù)資源權(quán)限配置,在響應(yīng)頭中放入Access-Control-Allow-Origin Header一罩、Access-Control-Allow-Methods和Access-Control-Allow-Headers Header杨幼,分別表示允許跨域資源請求的域、請求方法和請求頭聂渊。此外差购,服務(wù)器端還可以加入Access-Control-Max-Age Header,允許瀏覽器在指定時間內(nèi)汉嗽,無需再發(fā)送預(yù)檢請求進(jìn)行協(xié)商欲逃,直接用本次協(xié)商結(jié)果即可。瀏覽器根據(jù)OPTIONS請求返回的結(jié)果來決定是否繼續(xù)發(fā)送真實的請求進(jìn)行跨域資源訪問诊胞。這個過程對真實請求的調(diào)用者來說是透明的暖夭。
XMLHttpRequest支持通過withCredentials屬性實現(xiàn)在跨域請求攜帶身份信息(Credential锹杈,例如Cookie或者HTTP認(rèn)證信息)。瀏覽器將攜帶Cookie Header的請求發(fā)送到服務(wù)器端后迈着,如果服務(wù)器沒有響應(yīng)Access-Control-Allow-Credentials Header竭望,那么瀏覽器會忽略掉這次響應(yīng)。
這里討論的HTTP請求是指由Ajax XMLHttpRequest對象發(fā)起的裕菠,所有的CORS HTTP請求頭都可由瀏覽器填充咬清,無需在XMLHttpRequest對象中設(shè)置。以下是CORS協(xié)議規(guī)定的HTTP頭奴潘,用來進(jìn)行瀏覽器發(fā)起跨域資源請求時進(jìn)行協(xié)商:1. Origin旧烧。HTTP請求頭,任何涉及CORS的請求都必需攜帶画髓。2. Access-Control-Request-Method掘剪。HTTP請求頭,在帶預(yù)檢(Preflighted)的跨域請求中用來表示真實請求的方法奈虾。3. Access-Control-Request-Headers夺谁。HTTP請求頭,在帶預(yù)檢(Preflighted)的跨域請求中用來表示真實請求的自定義Header列表肉微。4. Access-Control-Allow-Origin匾鸥。HTTP響應(yīng)頭,指定服務(wù)器端允許進(jìn)行跨域資源訪問的來源域碉纳∥鸶海可以用通配符*表示允許任何域的JavaScript訪問資源,但是在響應(yīng)一個攜帶身份信息(Credential)的HTTP請求時劳曹,Access-Control-Allow-Origin必需指定具體的域奴愉,不能用通配符。5. Access-Control-Allow-Methods厚者。HTTP響應(yīng)頭躁劣,指定服務(wù)器允許進(jìn)行跨域資源訪問的請求方法列表,一般用在響應(yīng)預(yù)檢請求上库菲。6. Access-Control-Allow-Headers。HTTP響應(yīng)頭志膀,指定服務(wù)器允許進(jìn)行跨域資源訪問的請求頭列表熙宇,一般用在響應(yīng)預(yù)檢請求上。7. Access-Control-Max-Age溉浙。HTTP響應(yīng)頭烫止,用在響應(yīng)預(yù)檢請求上,表示本次預(yù)檢響應(yīng)的有效時間戳稽。在此時間內(nèi)馆蠕,瀏覽器都可以根據(jù)此次協(xié)商結(jié)果決定是否有必要直接發(fā)送真實請求期升,而無需再次發(fā)送預(yù)檢請求。 - Access-Control-Allow-Credentials互躬。HTTP響應(yīng)頭播赁,凡是瀏覽器請求中攜帶了身份信息,而響應(yīng)頭中沒有返回Access-Control-Allow-Credentials: true的吼渡,瀏覽器都會忽略此次響應(yīng)容为。
總結(jié):只要是帶自定義header的跨域請求,在發(fā)送真實請求前都會先發(fā)送OPTIONS請求寺酪,瀏覽器根據(jù)OPTIONS請求返回的結(jié)果來決定是否繼續(xù)發(fā)送真實的請求進(jìn)行跨域資源訪問坎背。所以復(fù)雜請求肯定會兩次請求服務(wù)端。
header('Access-Control-Allow-Origin:*'); //支持全域名訪問寄雀,不安全得滤,部署后需要固定限制為客戶端網(wǎng)址
header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支持的http 動作
header('Access-Control-Allow-Headers:x-requested-with,content-type'); //響應(yīng)頭 請按照自己需求添加。
$.ajax({
url: "http://test.com",
dataType: 'json',
type: 'GET',
beforeSend: function (xhr) {
xhr.setRequestHeader("Test", "testheadervalue");
},
async: false,
cache: false,
//contentType: 'application/x-www-form-urlencoded',
success: function (sResponse) {
}
});
如果是get請求盒犹,datatype也可以直接是jsonp懂更,如果是post請求,請在服務(wù)端設(shè)置header阿趁。