瀏覽器同源策略
同源策略是Web應(yīng)用程序安全模型中的一個(gè)重要概念。根據(jù)該策略,Web瀏覽器允許第一個(gè)Web頁(yè)面中包含的腳本訪問(wèn)第二個(gè)Web頁(yè)面中的數(shù)據(jù),但前提是兩個(gè)Web頁(yè)面具有相同的源。同源定義為協(xié)議,主機(jī)名和端口號(hào)相同的組合。此策略可防止一個(gè)頁(yè)面上的惡意腳本通過(guò)該頁(yè)面的文檔對(duì)象模型訪問(wèn)另一個(gè)網(wǎng)頁(yè)上的敏感數(shù)據(jù)
AJAX規(guī)避同源策略三種方式
JSONP:介紹可見(jiàn)參考資料;
WebCocket:使用ws://(非加密)和wss://(加密)作為協(xié)議前綴。該協(xié)議不實(shí)行同源政策,只要服務(wù)器支持,就可以通過(guò)它進(jìn)行跨源通信。
CORS(本文重點(diǎn)):跨源資源分享(Cross-Origin Resource Sharing)的縮寫(xiě)。它是W3C標(biāo)準(zhǔn),是跨源AJAX請(qǐng)求的根本解決方法。相比JSONP只能發(fā)GET請(qǐng)求,CORS允許任何類(lèi)型的請(qǐng)求。
Nginx通過(guò)CORS,實(shí)現(xiàn)跨域
Nginx標(biāo)準(zhǔn)配置
server {
... ...
# #設(shè)置跨域配置 Start
set $cors_origin "";
if ($http_origin ~* "^http://api.xx.com$"){
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,x-auth-token always;
add_header Access-Control-Max-Age 1728000 always;
# 預(yù)檢請(qǐng)求處理
if ($request_method = OPTIONS) {
return 204;
}
# #設(shè)置跨域配置 End
... ...
}
1.設(shè)置Origin:表示服務(wù)器可以接受的請(qǐng)求
add_header Access-Control-Allow-Origin http://api.baidu.com
表示 http://api.baidu.com 可以請(qǐng)求數(shù)據(jù)。這個(gè)可以設(shè)置為*星號(hào)代表任意跨源請(qǐng)求都支持,但不建議這樣設(shè)置;因?yàn)樵O(shè)置為*星號(hào)將不在支持發(fā)送Cookie。
2.設(shè)置多域名配置
set $cors_origin "";
if ($http_origin ~* "^http://api.xx.com$"){
set $cors_origin $http_origin;
}
if ($http_origin ~* "^http://api2.xx.com$"){
set $cors_origin $http_origin;
}
這個(gè)寫(xiě)法主要是為了支持多域名設(shè)置,通過(guò)對(duì)請(qǐng)求origin的判斷是否與指定跨域源一致,然后在進(jìn)行header的設(shè)置;
3.設(shè)置跨域支持的請(qǐng)求類(lèi)型
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS always;
4.設(shè)置跨域請(qǐng)求是否允許發(fā)送Cookie,true:支持,false:不支持
add_header Access-Control-Allow-Credentials true always;
5.設(shè)置跨域請(qǐng)求允許的Header頭信息字段,以逗號(hào)分隔的字符串
add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,x-auth-token always;
注:需要特別注意,凡是API中約定了自定義Header,都需要在這里增加,否則不可以跨域請(qǐng)求。
6.本次預(yù)檢請(qǐng)求的有效期,單位為秒,在允許緩存該條請(qǐng)求回應(yīng)1728000秒內(nèi),無(wú)需在發(fā)出一條預(yù)檢請(qǐng)求。
add_header Access-Control-Max-Age 1728000 always;
7.always 參數(shù)的定義
... ... always
Nginx 規(guī)則 add_header默認(rèn)只會(huì)加入到指定response code的請(qǐng)求中;
見(jiàn)官網(wǎng)介紹:
Syntax: add_header name value [always];
Default: —
Context: http, server, location, if in location
Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0). The value can contain variables.
指定了 always則無(wú)論什么請(qǐng)求都添加header:
If the always parameter is specified (1.7.5), the header field will be added regardless of the response code.
8.預(yù)檢請(qǐng)求處理
if ($request_method = OPTIONS) {
return 204;
}
CORS請(qǐng)求,會(huì)在正式通信之前,增加一次HTTP查詢(xún)請(qǐng)求,稱(chēng)為"預(yù)檢"請(qǐng)求(preflight);瀏覽器先詢(xún)問(wèn)服務(wù)器,當(dāng)前網(wǎng)頁(yè)所在的域名是否在服務(wù)器的許可名單之中,以及可以使用哪些HTTP動(dòng)詞和頭信息字段。只有得到肯定答復(fù),瀏覽器才會(huì)發(fā)出正式的XMLHttpRequest請(qǐng)求,否則就報(bào)錯(cuò)。
"預(yù)檢"請(qǐng)求用的請(qǐng)求方法是OPTIONS,表示這個(gè)請(qǐng)求是用來(lái)詢(xún)問(wèn)的,因此我們需要在Nginx配置中,針對(duì)預(yù)檢請(qǐng)求進(jìn)行處理,直接返回204 & Response Header,表示服務(wù)器支持允許跨源的訪問(wèn)。
AJAX配置
xhr.withCredentials = false;
CORS請(qǐng)求默認(rèn)不發(fā)送Cookie和HTTP認(rèn)證信息,如果需要支持除了服務(wù)端增加設(shè)置,AJAX請(qǐng)求中打開(kāi)withCredentials屬性。