如今“前后端分離”的設(shè)計(jì)思想已經(jīng)非常普及耳奕,所以一旦靜態(tài)資源和后臺(tái)應(yīng)用部署在不同服務(wù)器上并采用不同域名,那么,必然會(huì)遇到“瀏覽器同源策略”的限制身辨,也必然丐谋,需要前后臺(tái)一起合作解決跨域問題。
1. 同源策略
什么樣的URL是同源的煌珊?其必須滿足下面三個(gè)條件:
- 協(xié)議號(hào)相同
- 域名相同
- 端口相同
比如号俐,a.com網(wǎng)站,想要訪問b.com網(wǎng)站api定庵,比如api.b.com吏饿。那么,在“同源策略”限制下蔬浙,a.com網(wǎng)站無法獲取api.b.com下的cookie猪落,也無法向api.b.com發(fā)送ajax請(qǐng)求。
2. 如何支持跨域
最簡(jiǎn)單的方式是后臺(tái)服務(wù)器將允許跨域訪問的URL添加到白名單中畴博,這樣许布,前臺(tái)應(yīng)用不需要做任何特殊處理。
另外绎晃,還有兩種常用方法:
1) JSONP
基本思想為:網(wǎng)頁(yè)通過添加一個(gè)<script>元素蜜唾,向服務(wù)器請(qǐng)求JSON數(shù)據(jù),服務(wù)器收到請(qǐng)求后庶艾,將數(shù)據(jù)放在一個(gè)指定名字的回調(diào)函數(shù)里傳回來袁余。
用src屬性請(qǐng)求資源的標(biāo)簽,比如<link>咱揍,<img>颖榜,<script>
...都不受同源策略的限制。
<body>
<button onclick="loadData()">LoadData</button>
<script>
function foo(res){
console.log(res)
}
function loadData(){
var elem = document.createElement('script');
elem.src = 'http://a.com/jsonp?callback=foo';
document.head.appendChild(elem);
}
</script>
</body>
用JSONP煤裙,瀏覽器會(huì)自動(dòng)在request header里面帶上a.com
下的cookie信息掩完。
其實(shí),通過src調(diào)用api都是GET方式硼砰,類似請(qǐng)求資源文件且蓬,必須明確,從Web頁(yè)面產(chǎn)生的文件請(qǐng)求都會(huì)帶上cookie题翰。
因此恶阴,JSONP的缺點(diǎn)很明顯了:
- 只支持GET請(qǐng)求
- 只能帶本域下的cookies
2) CORS(Cross-origin resource sharing)
CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"豹障。它運(yùn)行瀏覽器向跨域服務(wù)器發(fā)送AJAX請(qǐng)求冯事。
小貼士
IE10以上用XMLHttpRequest對(duì)象實(shí)現(xiàn)CORS;
IE8血公,IE9用XDomainRequest支持CORS昵仅。
整個(gè)CORS跨域,是瀏覽器自動(dòng)完成累魔,不需要前端特殊處理摔笤。瀏覽器一旦發(fā)現(xiàn)是AJAX請(qǐng)求跨域够滑,會(huì)添加origin頭信息,后臺(tái)應(yīng)用需要根據(jù)request header中的origin/referer籍茧,來設(shè)置正確的response header版述,完成跨域請(qǐng)求梯澜。
CORS具體的概念和講解寞冯,網(wǎng)上很多資料,包括什么是簡(jiǎn)單請(qǐng)求和“Preflighted”晚伙,請(qǐng)參考 https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS吮龄。
下面要重點(diǎn)提到的是,CORS下咆疗,前端如何攜帶cookies?
Requests with credentials
用JS/JQuery啟動(dòng)AJAX請(qǐng)求時(shí)漓帚,必須設(shè)置withCredentials
頭為true,寫法如下:
JS:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('POST', ‘a(chǎn).com’, true);
xhr.send();
JQuery:
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
這時(shí)午磁,后臺(tái)設(shè)置response header時(shí)尝抖,需要返回:
Access-Control-Allow-Credentials: true;
Access-Control-Allow-Origin: a.com; //必須為具體域名,不能是*
重點(diǎn)需要注意的是cookies信息Q富省C亮伞!這時(shí)登颓,request請(qǐng)求中可以攜帶的cookies搅荞,不僅僅有本域下的cookies,還包括跨域服務(wù)器下設(shè)置的cookies(注意:跨域服務(wù)器下的cookies框咙,是無法通過JS代碼document.cookie
訪問咕痛,該cookies只能被遠(yuǎn)程服務(wù)器控制)。
可見喇嘱,在安全性上茉贡,CORS比JSONP強(qiáng)悍很多!
CORS缺點(diǎn)是者铜,低版本的IE瀏覽器支持不好块仆。
3. 小結(jié)
針對(duì)iframe,還有些特殊的解決跨域方式王暗,比如HTML5新特性:postMessage悔据。
如果父子窗口是同一個(gè)主域,不同子域俗壹,也可以通過設(shè)置document.domain
屬性科汗,規(guī)避同源策略。
微信公眾號(hào):