跨域常見解決方案
由於考慮到安全性問題,HTML的同源策略不允許JavaScript進行跨域操作,但是隨著web端功能越來越多,對跨域需求逐漸增大,於是乎便催生了很多解決跨域的方法,通過網絡搜索和資料查詢,主要比較常見的解決方案有以下幾種:
一、設置 document.domain
- 原理:相同主域名下不同子域頁面,通過設置document.domain讓他們同域;
- 限制:此方法只適用與跨子域的,對於跨父域名,仍然不可行,且需要載入iframe頁面。
// url http://bentos.com/foo var ifr = document.createElement(‘iframe‘); ifr.src
上述代碼所在的URL是
http://bentos.com/foo
,它對http://b.bentos.com/bar
document.domain
往上設置一級
// URL http://b.bentos.com/bar document.domain = ‘bentos.com‘ // URL: http://b.bentos.com/foo var data = { foo: ‘bar‘, bar: ‘foo‘ }; callback(data);
二、jsonp
- 原理:
<script>
是可以跨域的,而且在跨域腳本中可以直接回調當前腳本的函數。 - 限制:需要創建一個DOM對象並且添加到DOM樹,只能用於GET方法
// URL: http://b.bentos.com/foovar data = { foo: ‘bar‘, bar: ‘foo‘ }; callback(data);
// URL: http://bentos.com/foo var callback = function(data){ // 處理跨域請求得到的數據 }; var script = $(‘<script>‘, {src: ‘http://b.bentos.com/bar‘}); $(‘body‘).append(script);
三、navigation 對象
- 原理:iframe之間是共享
navigator
對象的,用它來傳遞信息 - 要求:IE6/7
有些人註意到了IE6/7的一個漏洞:iframe
之間的window.navigator
對象是共享的。 我們可以把它作為一個Messenger,通過它來傳遞信息。比如一個簡單的委托:
// bentos.com navigation.onData(){ // 數據到達的處理函數 } typeof navigation.getData === ‘function‘ || navigation.getData() // baidu.com navigation.getData = function(){ $.get(‘/path/under/baidu.com‘) .success(function(data){ typeof navigation.onData === ‘function‘ || navigation.onData(data) }); }
與document.navigator
類似,window.name
也是當前窗口所有頁面所共享的。也可以用它來傳遞信息。
四、window.postMessage
- 原理:HTML5允許窗口之間發送消息
- 限制:瀏覽器需要支持HTML5,獲取窗口句柄後才能相互通信
這是一個安全的跨域通信方法,postMessage(message,targetOrigin)
也是HTML5引入的特性。 可以給任何一個window發送消息,不論是否同源。第二個參數可以是*
但如果你設置了一個URL但不 相符,那麽該事件不會被分發。看一個普通的使用方式吧:
// URL: http://bentos.com/foo var win = window.open(‘http://b.com/bar‘); win.postMessage(‘Hello, bar!‘, ‘http://b.com‘); // URL: http://baidu.com/bar window.addEventListener(‘message‘,function(event) { console.log(event.data); });
註意IE8及小於IE8的版本不支持addEventListener
,需要使用attachEvent
來監聽事件。參見:事件處理中的this:attachEvent, addEventListener, onclick
五、跨域資源共享(CORS)
- 原理:服務器設置
Access-Control-Allow-Origin
HTTP響應頭之後,瀏覽器將會允許跨域請求 - 限制:瀏覽器需要支持HTML5,可以支持POST,PUT等方法
例如,從http://a.com
要訪問http://b.com
的數據,通常情況下Chrome會因跨域請求而報錯:
1 XMLHttpRequest cannot load http://b.com. No ‘Access-Control-Allow-Origin‘ header is present on the requested resource. Origin ‘http://a.com‘ is therefore not allowed access.
錯誤原因是被請求資源沒有設置Access-Control-Allow-Origin
,所以我們在b.com
的服務器中設置這個響應頭字段即可:
1 Access-Control-Allow-Origin: * # 允許所有域名訪問,或者 2 Access-Control-Allow-Origin: http://a.com # 只允許所有域名訪問
在Html5出來之前,跨域采用常見方法為jsonp,jQuery也給出了支持。 值得註意的是它只是Hack,並沒有產生額外的安全問題。 因為JSONP要成功獲取數據,需要跨域資源所在服務器的配合,比如資源所在服務器需要自願地回調一個合適的函數,所以服務器仍然有能力控制資源的跨域訪問。
跨域的正道還是要使用HTML5提供的CORS頭字段以及window.postMessage
, 可以支持POST, PUT等HTTP方法,從機制上解決跨域問題。 值得註意的是Access-Control-Allow-Origin
頭字段是資源所在服務器設置的, 訪問控制的責任仍然是在提供資源的服務器一方,這和JSONP是一樣的道理。
跨域常見解決方案