閱讀目錄
主要從事網(wǎng)頁(yè)設(shè)計(jì)、PC網(wǎng)站建設(shè)(電腦版網(wǎng)站建設(shè))、wap網(wǎng)站建設(shè)(手機(jī)版網(wǎng)站建設(shè))、響應(yīng)式網(wǎng)站設(shè)計(jì)、程序開發(fā)、微網(wǎng)站、小程序開發(fā)等,憑借多年來在互聯(lián)網(wǎng)的打拼,我們?cè)诨ヂ?lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)積累了豐富的成都做網(wǎng)站、網(wǎng)站建設(shè)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、網(wǎng)絡(luò)營(yíng)銷經(jīng)驗(yàn),集策劃、開發(fā)、設(shè)計(jì)、營(yíng)銷、管理等多方位專業(yè)化運(yùn)作于一體,具備承接不同規(guī)模與類型的建設(shè)項(xiàng)目的能力。
摘要:跨域問題,無論是面試還是平時(shí)的工作中,都會(huì)遇到,本文總結(jié)處理跨域問題的幾種方法以及其原理,也讓自己搞懂這方面的知識(shí),走起。
什么是跨域
在JavaScript中,有一個(gè)很重要的安全性限制,被稱為“Same-Origin Policy”(同源策略)。這一策略對(duì)于JavaScript代碼能夠訪問的頁(yè)面內(nèi)容做了很重要的限制,即JavaScript只能訪問與包含它的文檔在同一域下的內(nèi)容。
JavaScript這個(gè)安全策略在進(jìn)行多iframe或多窗口編程、以及Ajax編程時(shí)顯得尤為重要。根據(jù)這個(gè)策略,在baidu.com下的頁(yè)面中包含的JavaScript代碼,不能訪問在google.com域名下的頁(yè)面內(nèi)容;甚至不同的子域名之間的頁(yè)面也不能通過JavaScript代碼互相訪問。對(duì)于Ajax的影響在于,通過XMLHttpRequest實(shí)現(xiàn)的Ajax請(qǐng)求,不能向不同的域提交請(qǐng)求,例如,在abc.example.com下的頁(yè)面,不能向def.example.com提交Ajax請(qǐng)求,等等。
為什么瀏覽器要實(shí)現(xiàn)同源限制?我們舉例說明:
比如一個(gè)黑客,他利用iframe把真正的銀行登錄頁(yè)面嵌到他的頁(yè)面上,當(dāng)你使用真實(shí)的用戶名和密碼登錄時(shí),如果沒有同源限制,他的頁(yè)面就可以通過javascript讀取到你的表單中輸入的內(nèi)容,這樣用戶名和密碼就輕松到手了.
又比如你登錄了OSC,同時(shí)瀏覽了惡意網(wǎng)站,如果沒有同源限制,該惡意 網(wǎng)站就可以構(gòu)造AJAX請(qǐng)求頻繁在OSC發(fā)廣告帖.
跨域的情況分為以下幾種:

特別注意兩點(diǎn):
1、如果是協(xié)議和端口造成的跨域問題“前臺(tái)”是無能為力的
2、在跨域問題上,域僅僅是通過“URL的首部”來識(shí)別而不會(huì)去嘗試判斷相同的ip地址對(duì)應(yīng)著兩個(gè)域或兩個(gè)域是否在同一個(gè)ip上。比如上面的,http://www.a.com/a.js和http://70.32.92.74/b.js。雖然域名和域名的ip對(duì)應(yīng),不過還是被認(rèn)為是跨域。
“URL的首部”指window.location.protocol +window.location.host。其中,
window.location.protocol:指含有URL第一部分的字符串,如http:
window.location.host:指包含有URL中主機(jī)名:端口號(hào)部分的字符串.如//www.cenpok.net/server/
常用的幾種跨域處理方法:
1、JSONP
2、CORS策略
3、document.domain+iframe的設(shè)置
4、HTML5的postMessage
5、使用window.name來進(jìn)行跨域
跨域的原理解析及實(shí)現(xiàn)方法
1、JSONP(JSON with padding)
原理 :
我們知道,在頁(yè)面上有三種資源是可以與頁(yè)面本身不同源的。它們是:js腳本,css樣式文件,圖片,像淘寶等大型網(wǎng)站,肯定會(huì)將這些靜態(tài)資源放入cdn中,然后在頁(yè)面上連接,如下所示,所以它們是可以鏈接訪問到不同源的資源的。
1)<script type="text/javascript" src="某某cdn地址" ></script>
2)<link type="text/css" rel="stylesheet" href="某個(gè)cdn地址" />
3)<img src="某個(gè)cdn地址" />
而jsonp就是利用了script標(biāo)簽的src屬性是沒有跨域的限制的,從而達(dá)到跨域訪問的目的。因此它的最基本原理就是:動(dòng)態(tài)添加一個(gè)<script>標(biāo)簽來實(shí)現(xiàn)。
實(shí)現(xiàn)方法:
這里是使用ajax來請(qǐng)求的,看起來和ajax沒啥區(qū)別,其實(shí)還是有區(qū)別的。
ajax的核心是通過XmlHttpRequest獲取非本頁(yè)內(nèi)容,而jsonp的核心則是動(dòng)態(tài)添加<script>標(biāo)簽來調(diào)用服務(wù)器提供的js腳本。
$.ajax({
url:"http://crossdomain.com/services.php",
dataType:'jsonp',
data:'',
jsonp:'callback',
success:function(result) {
// some code
}
});上面的代碼中,callback是必須的,callback是什么值要跟后臺(tái)拿。獲取到的jsonp數(shù)據(jù)格式如下:
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});jsonp的全稱為json with padding,上面的數(shù)據(jù)中,flightHandler就是那個(gè)padding.
JSONP的不足之處:
1、只能使用get方法,不能使用post方法:
我們知道 script,link, img 等等標(biāo)簽引入外部資源,都是 get 請(qǐng)求的,那么就決定了 jsonp 一定是 get 的。但有時(shí)候我們使用的 post 請(qǐng)求也成功,為啥呢?這是因?yàn)楫?dāng)我們指定dataType:'jsonp',不論你指定:type:"post" 或者type:"get",其實(shí)質(zhì)上進(jìn)行的都是 get 請(qǐng)求!
2、沒有關(guān)于 JSONP 調(diào)用的錯(cuò)誤處理。如果動(dòng)態(tài)腳本插入有效,就執(zhí)行調(diào)用;如果無效,就靜默失敗。失敗是沒有任何提示的。例如,不能從服務(wù)器捕捉到 404 錯(cuò)誤,也不能取消或重新開始請(qǐng)求。不過,等待一段時(shí)間還沒有響應(yīng)的話,就不用理它了。
2、CORS策略
原理:
CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請(qǐng)求,從而克服了AJAX只能同源使用的限制。它為Web服務(wù)器定義了一種方式,允許網(wǎng)頁(yè)從不同的域訪問其資源.
CORS系統(tǒng)定義了一種瀏覽器和服務(wù)器交互的方式來確定是否允許跨域請(qǐng)求。 它是一個(gè)妥協(xié),有更大的靈活性,但比起簡(jiǎn)單地允許所有這些的要求來說更加安全。
實(shí)現(xiàn)方法:
CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。
整個(gè)CORS通信過程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺。
前端方面
以前我們使用Ajax,代碼類似于如下的方式:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/hfahe", true);
xhr.send();
// 這里的“/hfahe”是本域的相對(duì)路徑。如果我們要使用CORS,相關(guān)Ajax代碼可能如下所示:
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://blog.csdn.net/hfahe", true);
xhr.send();
// 請(qǐng)注意,代碼與之前的區(qū)別就在于相對(duì)路徑換成了其他域的絕對(duì)路徑,也就是你要跨域訪問的接口地址。服務(wù)器方面
服務(wù)器端對(duì)于CORS的支持,主要就是通過設(shè)置Access-Control-Allow-Origin來進(jìn)行的。如果瀏覽器檢測(cè)到相應(yīng)的設(shè)置,就可以允許Ajax進(jìn)行跨域的訪問。
CORS策略的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
1、CORS支持所有類型的HTTP請(qǐng)求。
2、 使用CORS,開發(fā)者可以使用普通的XMLHttpRequest發(fā)起請(qǐng)求和獲得數(shù)據(jù),比起JSONP有更好的錯(cuò)誤處理。
缺點(diǎn): 兼容性方面相對(duì)差一點(diǎn),ie10或以上才支持
3、document.domain+iframe的設(shè)置 (只有在主域相同的時(shí)候才能使用該方法)
原理:
瀏覽器中不同域的框架之間是不能進(jìn)行js的交互操作的。但是不同的框架之間(父子或同輩),是能夠獲取到彼此的window對(duì)象的,但是,我們也只能獲取到一個(gè)幾乎
無用的window對(duì)象。比如,有一個(gè)頁(yè)面,它的地址是 http://www.example.com/a.html , 在這個(gè)頁(yè)面里面有一個(gè)iframe,它的src是 http://example.com/b.html , 很顯然,這
個(gè)頁(yè)面與它里面的iframe框架是不同域的,所以我們是無法通過在頁(yè)面中書寫js代碼來獲取iframe中的東西的。
這個(gè)時(shí)候,document.domain就可以派上用場(chǎng)了,我們只要把 http://www.example.com/a.html 和 http://example.com/b.html 這兩個(gè)頁(yè)面的document.domain都設(shè)成
相同的域名就可以了。但要注意的是,document.domain的設(shè)置是有限制的,我們只能把document.domain設(shè)置成自身或更高一級(jí)的父域,且主域必須相同。例如:
a.b.example.com 中某個(gè)文檔的document.domain 可以設(shè)成a.b.example.com、b.example.com 、example.com中的任意一個(gè),但是不可以設(shè)成 c.a.b.example.com,因?yàn)檫@是
當(dāng)前域的子域,也不可以設(shè)成baidu.com,因?yàn)橹饔蛞呀?jīng)不相同了。
使用方法:
比如在http://www.example.com/a.html 的頁(yè)面里要訪問 http://example.com/b.html里面的東西。
在頁(yè)面 http://www.example.com/a.html 中設(shè)置document.domain:
//http://www.example.com/a.html
<html>
<head>
<title>A頁(yè)面</title>
<script type="text/javascript" src="jquery.js"></script>
</head>
<body>
<div>A頁(yè)面</div>
<iframe id="iframe" src="http://example.com/b.html" ></iframe>
// 相當(dāng)于用一個(gè)隱藏的iframe來做代理
<script>
$(function(){
try{
document.domain = "example.com"; //這里將document.domain設(shè)置成一樣
}catch(e){}
$("#iframe").load(function(){
var iframe = $("#iframe").contentDocument.$;
ifram.get("http://example.com/接口",function(data){});
});
});
</script>
<body>
</html>在頁(yè)面 http://example.com/b.html 中也設(shè)置document.domain,而且這也是必須的,雖然這個(gè)文檔的domain就是example.com,但是還是必須顯示的設(shè)置document.domain的值:
//http://example.com/b.html
<html>
<head>
<title>B頁(yè)面</title>
<script type="text/javascript" src="jquery.js"></script>
</head>
<body>
<div>B頁(yè)面</div>
<script>
$(function(){
try{
document.domain = "example.com"; //這里將document.domain設(shè)置成一樣
}catch(e){}
});
</script>
</body>
</html>這里有個(gè)注意點(diǎn),就是在A頁(yè)面中,要等iframe標(biāo)簽完成加載B頁(yè)面之后,再取iframe對(duì)象的contentDocument,否則如果B頁(yè)面沒有被iframe完全加載,在A頁(yè)面中通過contentDocument屬性就取不到B頁(yè)面中的jQuery對(duì)象。
一旦取到B頁(yè)面中的jQuery對(duì)象,就可以直接發(fā)ajax請(qǐng)求了,這種類似“代理”方式可以解決主子域的跨域問題。
缺點(diǎn):
只有在主域相同的時(shí)候才能使用該方法
4、HTML5的postMessage
原理:
沒啥原理,就是一個(gè)html5所提供的一個(gè)API.--->HTML5 window.postMessage是一個(gè)安全的、基于事件的消息API。
在需要發(fā)送消息的源窗口調(diào)用postMessage方法即可發(fā)送消息。其中.源窗口可以是全局的window對(duì)象,也可以是以下類型的窗口:
1、文檔窗口中的iframe:
var iframe = document.getElementById('my-iframe');
var win = iframe.documentWindow;2、JavaScript打開的彈窗:
var win = window.open();
3、當(dāng)前文檔窗口的父窗口:
var win = window.parent;
4、
var win = window.opener();
發(fā)送消息:找到源window對(duì)象后,即可調(diào)用postMessage API向目標(biāo)窗口發(fā)送消息:
win.postMessage(msg, targetOrigin);
說明:postMessage函數(shù)接收兩個(gè)參數(shù):
1、msg, 將要發(fā)送的消息,可以使一切javascript參數(shù),如字符串,數(shù)字,對(duì)象,數(shù)組等。
2、targetOrigin,這個(gè)參數(shù)稱作“目標(biāo)域”,注意,是目標(biāo)域不是本域!比如,你想在2.com的網(wǎng)頁(yè)上往1.com網(wǎng)頁(yè)上傳消息,那么這個(gè)參數(shù)就是“http://1.com/”,而不是2.com.協(xié)議,(一個(gè)完整的域名包括:主機(jī)名,端口號(hào)。如:http://g.cn:80/)
接收消息:那目標(biāo)窗口要怎么接收傳過來的數(shù)據(jù)呢,只要監(jiān)聽window的message事件就可以接收了。
var onmessage = function (event) {
var data = event.data;
var origin = event.origin;
//do someing
};
if (typeof window.addEventListener != 'undefined') {
window.addEventListener('message', onmessage, false);
} else if (typeof window.attachEvent != 'undefined') {
//for ie
window.attachEvent('onmessage', onmessage);
}message事件監(jiān)聽函數(shù)接收一個(gè)參數(shù),Event對(duì)象實(shí)例,該對(duì)象有三個(gè)屬性:
使用方法(案例):
http://test.com/index.html--> 發(fā)送消息的頁(yè)面
<!-- 這個(gè)是 http://test.com/index.html 頁(yè)面 -->
<div>
<!-- 要給下面的頁(yè)面?zhèn)饕粋€(gè)妹子過去 -->
<iframe id="child" src="http://lsLib.com/lsLib.html"></iframe>
</div>
<script type="text/javascript">
window.onload=function(){
window.frames[0].postMessage('蒼老師','http://lslib.com');
}
</script>http://lslib.com/lslib.html --> 接收消息的頁(yè)面
<!-- 這個(gè)是 http://lslib.com/lslib.html 頁(yè)面 -->
<script type="text/javascript">
window.addEventListener('message',function (e) {
console.log(e.origin,e.data);
alert('收到妹子一枚:'+e.data);
});
</script>優(yōu)缺點(diǎn):
優(yōu)點(diǎn):方便,安全,有效的解決了跨域問題
缺點(diǎn):萬(wàn)惡的資本主義,ie8+才支持,而且ie8+<ie10只支持iframe的方式。
5、使用window.name來進(jìn)行跨域(相對(duì)比較完美的方法)
原理:
當(dāng)iframe的頁(yè)面跳到其他地址時(shí),其window.name值保持不變,并且可以支持非常長(zhǎng)的 name 值(2MB)。
瀏覽器跨域iframe禁止互相調(diào)用/傳值.但是調(diào)用iframe時(shí) window.name 卻不變,正是利用這個(gè)特性來互相傳值,當(dāng)然跨域下是不容許讀取ifram的window.name值.
所以這里我們還要準(zhǔn)備一個(gè)和主頁(yè)面http://www.a.com/main.html 相同域下的代理頁(yè)面http://www.a.com/other.html ,iframe調(diào)用子頁(yè)面 http://www.b.com/data.html
使用方法:
1、準(zhǔn)備三個(gè)頁(yè)面:
http://www.a.com/main.html //應(yīng)用頁(yè)面
http://www.a.com/other.html // 代理頁(yè)面,要求和應(yīng)用頁(yè)面在同一個(gè)域。一般是一個(gè)空的html
http://www.b.com/data.html //應(yīng)用頁(yè)面獲取數(shù)據(jù)的頁(yè)面,簡(jiǎn)稱:數(shù)據(jù)頁(yè)面
2、數(shù)據(jù)頁(yè)面將數(shù)據(jù)傳到window.name中去。如下:
http://www.b.com/data.html中的 data.html
// data.html window.name="蒼老師"; //可以是其他類型的數(shù)據(jù),比如數(shù)組,對(duì)象等等
http://www.a.com/main.html //應(yīng)用頁(yè)面的代碼如下:
<!-- main.html -->
var iframeData;
var state = 0;//開關(guān)變量
var iframe = document.createElement('iframe'); //創(chuàng)建iframe
var loadfn = function() {
if (state === 1) {
iframeData = iframe.contentWindow.name; // 讀取數(shù)據(jù)
alert('獲取到了iframe傳過來的妹子'+iframeData);
}else if (state === 0) {
state = 1;
iframe.contentWindow.location = 'http://www.a.com/other.html'; //這里是代理頁(yè)面 other.html
/**
這里說明一下:
由于iframe的location改變了,相當(dāng)于重新載入頁(yè)面(這是iframe的性質(zhì)決定的),于是重新執(zhí)行l(wèi)oadfn方法。
由于當(dāng)iframe的頁(yè)面跳到其他地址時(shí),其window.name值保持不變,并且此時(shí)開關(guān)變量 state已經(jīng)變?yōu)?,
于是就可以獲取到window.name值,也就達(dá)到了跨域訪問的目的了。
**/
};
}
iframe.src = 'http://www.b.com/data.html'; //這是是數(shù)據(jù)頁(yè)面,data.html
if (iframe.attachEvent) {
iframe.attachEvent('onload', loadfn);
} else {
iframe.onload = loadfn;
}
document.body.appendChild(iframe);
3、獲取數(shù)據(jù)以后銷毀這個(gè)iframe,釋放內(nèi)存;這也保證了安全(不被其他域frame js訪問)。
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);優(yōu)缺點(diǎn):
瀏覽器支持情況好,是比較普遍的使用方法
總結(jié)
以上總結(jié)了js跨域的幾種方法,當(dāng)然還有其他的方法,不過沒有。他們各有千秋。其實(shí)最主要的區(qū)別除了實(shí)現(xiàn)方式不一樣,主要是瀏覽器的兼容問題而已。
JSONP:
JSONP的優(yōu)點(diǎn)是:它不像XMLHttpRequest對(duì)象實(shí)現(xiàn)的Ajax請(qǐng)求那樣受到同源策略的限制;它的兼容性更好,在更加古老的瀏覽器中都可以運(yùn)行,不需要XMLHttpRequest或ActiveX的支持;并且在請(qǐng)求完畢后可以通過調(diào)用callback的方式回傳結(jié)果。
JSONP的缺點(diǎn)則是:它只支持GET請(qǐng)求而不支持POST等其它類型的HTTP請(qǐng)求;它只支持跨域HTTP請(qǐng)求這種情況,不能解決不同域的兩個(gè)頁(yè)面之間如何進(jìn)行JavaScript調(diào)用的問題。
CORS策略
優(yōu)點(diǎn):使用CORS,開發(fā)者可以使用普通的XMLHttpRequest發(fā)起請(qǐng)求和獲得數(shù)據(jù),比起JSONP有更好的錯(cuò)誤處理。
缺點(diǎn):古老的瀏覽器不支持,不過大部分現(xiàn)代瀏覽器都支持
document.domain+iframe:只適用于主域相同的跨域問題處理
html5的postMessage:
優(yōu)點(diǎn):是html5新引進(jìn)的特性,可以使用它來向其它的window對(duì)象發(fā)送消息,無論這個(gè)window對(duì)象是屬于同源或不同源,目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經(jīng)支持window.postMessage方法。如果是現(xiàn)代瀏覽器,首選。
缺點(diǎn): ie8以前不支持
window.name:
主要是應(yīng)用當(dāng)frame的頁(yè)面跳到其他地址時(shí),其window.name值保持不變的原理。兼容性好。需要照顧落后的瀏覽器時(shí),首選。
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持創(chuàng)新互聯(lián)!
當(dāng)前標(biāo)題:老生常談的跨域處理
當(dāng)前URL:http://www.chinadenli.net/article22/gccjcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、自適應(yīng)網(wǎng)站、網(wǎng)站設(shè)計(jì)公司、網(wǎng)頁(yè)設(shè)計(jì)公司、網(wǎng)站收錄、品牌網(wǎng)站設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)