前言
本文主要給大家介紹了關(guān)于web開發(fā)之跨域的解決方案,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧。
什么是跨域?
概念如下:只要協(xié)議、域名、端口有任何一個(gè)不同,都被當(dāng)作是不同的域
下面是具體的跨域情況詳解
URL | 說明 | 是否允許通信 |
---|---|---|
http://www.a.com/a.js、http://www.a.com/b.js | 同一域名下 | 允許 |
http://www.a.com/lab/a.js、http://www.a.com/script/b.js | 同一域名下不同文件夾 | 允許 |
http://www.a.com:8000/a.js、http://www.a.com/b.js | 同一域名,不同端口 | 不允許 |
http://www.a.com/a.js、https://www.a.com/b.js | 同一域名,不同協(xié)議 | 不允許 |
http://www.a.com/a.js、http://70.32.92.74/b.js | 域名和域名對(duì)應(yīng)ip | 不允許 |
http://www.a.com/a.js、http://script.a.com/b.js | 主域相同,子域不同 | 不允許(cookie這種情況下也不允許訪問) |
http://www.a.com/a.js、http://a.com/b.js | 同一域名,不同二級(jí)域名(同上) | 不允許(cookie這種情況下也不允許訪問) |
http://www.cnblogs.com/a.js、http://www.a.com/b.js | 不同域名 | 不允許 |
一、document.domain跨域
原理:相同主域名不同子域名下的頁面,可以設(shè)置document.domain
讓它們同域
限制:同域document提供的是頁面間的互操作,需要載入iframe頁面
下面幾個(gè)域名下的頁面都是可以通過document.domain跨域互操作的: http://a.com/foo, http://b.a.com/bar, http://c.a.com/bar。 但只能以頁面嵌套的方式來進(jìn)行頁面互操作,比如常見的iframe方式就可以完成頁面嵌套
// URL http://a.com/foovar ifr = document.createElement('iframe');ifr.src = 'http://b.a.com/bar'; ifr.onload = function(){ var ifrdoc = ifr.contentDocument || ifr.contentWindow.document; ifrdoc.getElementsById("foo").innerHTML);};ifr.style.display = 'none';document.body.appendChild(ifr);
上述代碼所在的URL是http://a.com/foo,它對(duì)http://b.a.com/bar的DOM訪問要求后者將 document.domain往上設(shè)置一級(jí)
// URL http://b.a.com/bardocument.domain = 'a.com'
document.domain只能從子域設(shè)置到主域,往下設(shè)置以及往其他域名設(shè)置都是不允許的, 在Chrome中給出的錯(cuò)誤是這樣的
Uncaught DOMException: Failed to set the 'domain' property on 'Document': 'baidu.com' is not a suffix of 'b.a.com'
二、有src的標(biāo)簽
原理:所有具有src屬性的HTML標(biāo)簽都是可以跨域的,包括<img>, <script>
限制:需要?jiǎng)?chuàng)建一個(gè)DOM對(duì)象,只能用于GET方法
在document.body
中append一個(gè)具有src屬性的HTML標(biāo)簽, src屬性值指向的URL會(huì)以GET方法被訪問,該訪問是可以跨域的
其實(shí)樣式表的<link>標(biāo)簽也是可以跨域的,只要是有src或href的HTML標(biāo)簽都有跨域的能力
不同的HTML標(biāo)簽發(fā)送HTTP請(qǐng)求的時(shí)機(jī)不同,例如<img>在更改src屬性時(shí)就會(huì)發(fā)送請(qǐng)求,而script, iframe, link[rel=stylesheet]
只有在添加到DOM樹之后才會(huì)發(fā)送HTTP請(qǐng)求:
var img = new Image();img.src = 'http://some/picture'; // 發(fā)送HTTP請(qǐng)求var ifr = $('<iframe>', {src: 'http://b.a.com/bar'});$('body').append(ifr); // 發(fā)送HTTP請(qǐng)求
三、JSONP
原理:<script>是可以跨域的,而且在跨域腳本中可以直接回調(diào)當(dāng)前腳本的函數(shù)
限制:需要?jiǎng)?chuàng)建一個(gè)DOM對(duì)象并且添加到DOM樹,只能用于GET方法
JSONP利用的是<script>可以跨域的特性,跨域URL返回的腳本不僅包含數(shù)據(jù),還包含一個(gè)回調(diào)
// URL: http://b.a.com/foovar data = { foo: 'bar', bar: 'foo'};callback(data);
然后在我們?cè)谥髡緃ttp://a.com中,可以這樣來跨域獲取http://b.a.com的數(shù)據(jù):
// URL: http://a.com/foovar callback = function(data){ // 處理跨域請(qǐng)求得到的數(shù)據(jù)};var script = $('<script>', {src: 'http://b.a.com/bar'});$('body').append(script);
其實(shí)jQuery已經(jīng)封裝了JSONP的使用,我們可以這樣來
$.getJSON( "http://b.a.com/bar?callback=callback", function( data ){ // 處理跨域請(qǐng)求得到的數(shù)據(jù)});
$.getJSON與$.get的區(qū)別是前者會(huì)把responseText轉(zhuǎn)換為JSON,而且當(dāng)URL具有callback參數(shù)時(shí), jQuery將會(huì)把它解釋為一個(gè)JSONP請(qǐng)求,創(chuàng)建一個(gè)<script>標(biāo)簽來完成該請(qǐng)求
四、navigation 對(duì)象
原理:iframe之間是共享navigator對(duì)象的,用它來傳遞信息
要求:IE6/7
有些人注意到了IE6/7的一個(gè)漏洞:iframe之間的window.navigator
對(duì)象是共享的。 我們可以把它作為一個(gè)Messenger,通過它來傳遞信息。比如一個(gè)簡(jiǎn)單的委托:
// a.comnavigation.onData(){ // 數(shù)據(jù)到達(dá)的處理函數(shù)}typeof navigation.getData === 'function' || navigation.getData()
// b.comnavigation.getData = function(){ $.get('/path/under/b.com') .success(function(data){ typeof navigation.onData === 'function' || navigation.onData(data) });}
與document.navigator
類似,window.name
也是當(dāng)前窗口所有頁面所共享的。也可以用它來傳遞信息。 同樣蛋疼的辦法還有傳遞Hash(有些人叫錨點(diǎn)),這是因?yàn)槊看螢g覽器打開一個(gè)URL時(shí),URL后面的#xxx部分會(huì)保留下來,那么新的頁面可以從這里獲得上一個(gè)頁面的數(shù)據(jù)
五、跨域資源共享(CORS)
原理:服務(wù)器設(shè)置Access-Control-Allow-OriginHTTP響應(yīng)頭之后,瀏覽器將會(huì)允許跨域請(qǐng)求
限制:瀏覽器需要支持HTML5,可以支持POST,PUT等方法
前面提到的跨域手段都是某種意義上的Hack, HTML5標(biāo)準(zhǔn)中提出的跨域資源共享(Cross Origin Resource Share,CORS)才是正道。 它支持其他的HTTP方法如PUT, POST等,可以從本質(zhì)上解決跨域問題。
例如,從http://a.com要訪問http://b.com的數(shù)據(jù),通常情況下Chrome會(huì)因跨域請(qǐng)求而報(bào)錯(cuò)
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
錯(cuò)誤原因是被請(qǐng)求資源沒有設(shè)置Access-Control-Allow-Origin,所以我們?cè)赽.com的服務(wù)器中設(shè)置這個(gè)響應(yīng)頭字段即可
Access-Control-Allow-Origin: * # 允許所有域名訪問,或者Access-Control-Allow-Origin: http://a.com # 只允許所有域名訪問
六、window.postMessage
原理:HTML5允許窗口之間發(fā)送消息
限制:瀏覽器需要支持HTML5,獲取窗口句柄后才能相互通信
這是一個(gè)安全的跨域通信方法,postMessage(message,targetOrigin)
也是HTML5引入的特性。 可以給任何一個(gè)window發(fā)送消息,不論是否同源。第二個(gè)參數(shù)可以是*但如果你設(shè)置了一個(gè)URL但不相符,那么該事件不會(huì)被分發(fā)。看一個(gè)普通的使用方式吧
// URL: http://a.com/foovar win = window.open('http://b.com/bar');win.postMessage('Hello, bar!', 'http://b.com');
// URL: http://b.com/barwindow.addEventListener('message',function(event) { console.log(event.data);});
七、訪問控制安全的討論
在HTML5之前,JSONP已經(jīng)成為跨域的事實(shí)標(biāo)準(zhǔn)了,jQuery都給出了支持。 值得注意的是它只是Hack,并沒有產(chǎn)生額外的安全問題。 因?yàn)镴SONP要成功獲取數(shù)據(jù),需要跨域資源所在服務(wù)器的配合,比如資源所在服務(wù)器需要自愿地回調(diào)一個(gè)合適的函數(shù),所以服務(wù)器仍然有能力控制資源的跨域訪問
跨域的正道還是要使用HTML5提供的CORS頭字段以及window.postMessage
, 可以支持POST, PUT等HTTP方法,從機(jī)制上解決跨域問題。 值得注意的是Access-Control-Allow-Origin頭字段是資源所在服務(wù)器設(shè)置的, 訪問控制的責(zé)任仍然是在提供資源的服務(wù)器一方,這和JSONP是一樣的
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)武林網(wǎng)的支持。
新聞熱點(diǎn)
疑難解答
圖片精選