[HTTP趣談]支持跨域及相關cookie設置
如今“前後端分離”的設計思想已經非常普及,所以一旦靜態資源和後臺應用部署在不同服務器上並採用不同域名,那麼,必然會遇到“瀏覽器同源策略”的限制,也必然,需要前後臺一起合作解決跨域問題。
1. 同源策略
什麼樣的URL是同源的?其必須滿足下面三個條件:
- 協議號相同
- 域名相同
- 端口相同
比如,a.com網站,想要訪問b.com網站api,比如api.b.com。那麼,在“同源策略”限制下,a.com網站無法獲取api.b.com下的cookie,也無法向api.b.com發送ajax請求。
2. 如何支持跨域
最簡單的方式是後臺服務器將允許跨域訪問的URL添加到白名單中,這樣,前臺應用不需要做任何特殊處理。
另外,還有兩種常用方法:
1) JSONP
基本思想爲:網頁通過添加一個
<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,瀏覽器會自動在request header裏面帶上a.com
下的cookie信息。
其實,通過src調用api都是GET方式,類似請求資源文件,必須明確,從Web頁面產生的文件請求都會帶上cookie。
因此,JSONP的缺點很明顯了:
- 只支持GET請求
- 只能帶本域下的cookies
2) CORS(Cross-origin resource sharing)
CORS是一個W3C標準,全稱是”跨域資源共享”。它運行瀏覽器向跨域服務器發送AJAX請求。
小貼士
IE10以上用XMLHttpRequest對象實現CORS;
IE8,IE9用XDomainRequest支持CORS。
整個CORS跨域,是瀏覽器自動完成,不需要前端特殊處理。瀏覽器一旦發現是AJAX請求跨域,會添加origin頭信息,後臺應用需要根據request header中的origin/referer,來設置正確的response header,完成跨域請求。
cors.png
CORS具體的概念和講解,網上很多資料,包括什麼是簡單請求和“Preflighted”,請參考 https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS。
下面要重點提到的是,CORS下,前端如何攜帶cookies?
Requests with credentials
用JS/JQuery啓動AJAX請求時,必須設置withCredentials
頭爲true,寫法如下:
JS:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('POST', ‘a.com’, true);
xhr.send();
JQuery:
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
這時,後臺設置response header時,需要返回:
Access-Control-Allow-Credentials: true;
Access-Control-Allow-Origin: a.com; //必須爲具體域名,不能是*
重點需要注意的是cookies信息!!!這時,request請求中可以攜帶的cookies,不僅僅有本域下的cookies,還包括跨域服務器下設置的cookies(注意:跨域服務器下的cookies,是無法通過JS代碼document.cookie
訪問,該cookies只能被遠程服務器控制)。
可見,在安全性上,CORS比JSONP強悍很多!
CORS缺點是,低版本的IE瀏覽器支持不好。
3. 小結
針對iframe,還有些特殊的解決跨域方式,比如HTML5新特性:postMessage。
如果父子窗口是同一個主域,不同子域,也可以通過設置document.domain
屬性,規避同源策略。