久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

深入理解前端跨域方法和原理

 liang1234_ 2017-02-27

前言


受瀏覽器同源策略的限制,,本域的js不能操作其他域的頁面對(duì)象(比如DOM),。但在安全限制的同時(shí)也給注入iframe或是ajax應(yīng)用上帶來了不少麻煩。所以我們要通過一些方法使本域的js能夠操作其他域的頁面對(duì)象或者使其他域的js能操作本域的頁面對(duì)象(iframe之間),。


這里需要明確的一點(diǎn)是:所謂的域跟js的存放服務(wù)器沒有關(guān)系,,比如baidu.com的頁面加載了google.com的js,那么此js的所在域是baidu.com而不是google.com,。也就是說,,此時(shí)該js能操作baidu.com的頁面對(duì)象,而不能操作google.com的頁面對(duì)象,。


跨域的方法總結(jié)


單向跨域(一般用于獲取數(shù)據(jù))


一、使用JSONP跨域


原理:因?yàn)橥ㄟ^script標(biāo)簽引入的js是不受同源策略的限制的(正如前文提到的baidu.com的頁面加載了google.com的js),。所以我們可以通過script標(biāo)簽引入一個(gè)js或者是一個(gè)其他后綴形式(如php,,jsp等)的文件,此文件返回一個(gè)js函數(shù)的調(diào)用,,如返回JSONP_getUsers(['paco','john','lili']),,也就是說此文件返回的結(jié)果調(diào)用了JSONP_getUsers函數(shù),并且把['paco','john','lili']傳進(jìn)去,,這個(gè)['paco','john','lili']是一個(gè)用戶列表,。那么如果此時(shí)我們的頁面中有一個(gè)JSONP_getUsers函數(shù),那么JSONP_getUsers就被調(diào)用到,,并且傳入了用戶列表,。此時(shí)就實(shí)現(xiàn)了在本域獲取其他域數(shù)據(jù)的功能,也就是跨域。

實(shí)現(xiàn)例子如下:

前端引入遠(yuǎn)程js并定義好JSONP_getUsers函數(shù),,注意需要先定義好JSONP_getUsers函數(shù),,避免在遠(yuǎn)程js加載完成并調(diào)用JSONP_getUsers時(shí),此函數(shù)不存在:

//本域?yàn)閎aidu.com <script> function JSONP_getUsers(users){ console.dir(users); } </script> //加載google.com的getUsers.php <script src='http://www.google.com/getUsers.php'></script>

需要google.com提供支持,,getUsers.php代碼如下:

<?php> echo 'JSONP_getUsers(['paco','john','lili'])';//返回一個(gè)js函數(shù)的調(diào)用 ?>

為什么script標(biāo)簽引入的文件不受同源策略的限制,?因?yàn)閟cript標(biāo)簽引入的文件內(nèi)容是不能夠被客戶端的js獲取到的,不會(huì)影響到被引用文件的安全,,所以沒必要使script標(biāo)簽引入的文件遵循瀏覽器的同源策略,。而通過ajax加載的文件內(nèi)容是能夠被客戶端js獲取到的,所以ajax必須遵循同源策略,,否則被引入文件的內(nèi)容會(huì)泄漏或者存在其他風(fēng)險(xiǎn),。


JSONP的缺點(diǎn)則是:它只支持GET請(qǐng)求而不支持POST等其它類型的HTTP請(qǐng)求(雖然采用post 動(dòng)態(tài)生成iframe是可以達(dá)到post跨域的目的,但這樣做是一個(gè)比較極端的方式,,不建議采用),。一般get請(qǐng)求能完成所有功能。比如如果需要給其他域服務(wù)器傳送參數(shù)可以在請(qǐng)求后掛參數(shù)(注意不要掛隱私數(shù)據(jù)),,即

<script src='http://www.google.com/getUsers.php?flag=do&time=1'></script>,。
JSONP易于實(shí)現(xiàn),但是也會(huì)存在一些安全隱患,,如果第三方的腳本隨意地執(zhí)行,,那么它就可以篡改頁面內(nèi)容,截獲敏感數(shù)據(jù),。但是在受信任的雙方傳遞數(shù)據(jù),,JSONP是非常合適的選擇??梢钥闯鰜鞪SONP跨域一般用于獲取其他域的數(shù)據(jù),。


一般能夠用JSONP實(shí)現(xiàn)跨域就用JSONP實(shí)現(xiàn),這也是前端用的最多的跨域方法,。


二,、動(dòng)態(tài)創(chuàng)建script標(biāo)簽


這種方法其實(shí)是JSONP跨域的簡(jiǎn)化版,JSONP只是在此基礎(chǔ)上加入了回調(diào)函數(shù),。

比如上例中的getUsers.php返回的如果不是一個(gè)js函數(shù)的調(diào)用,,而是一個(gè)js變量,如:

<?php> echo 'var users=['paco','john','lili']';//返回一個(gè)js變量users ?>
那么在本域下就可以取到data變量,,這里需要注意判斷script節(jié)點(diǎn)是否加載完畢,,如:

js.onload = js.onreadystatechange = function() { if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') { console.log(users);//此處取出其他域的數(shù)據(jù) js.onload = js.onreadystatechange = null; } };

三、flash URLLoader


flash有自己的一套安全策略,,服務(wù)器可以通過crossdomain.xml文件來聲明能被哪些域的SWF文件訪問,,SWF也可以通過API來確定自身能被哪些域的SWF加載,。當(dāng)跨域訪問資源時(shí),例如從域baidu.com請(qǐng)求域google.com上的數(shù)據(jù),,我們可以借助flash來發(fā)送HTTP請(qǐng)求,。首先,修改域google.com上的crossdomain.xml(一般存放在根目錄,,如果沒有需要手動(dòng)創(chuàng)建) ,,把baidu.com加入到白名單。其次,,通過Flash URLLoader發(fā)送HTTP請(qǐng)求,,最后,通過Flash API把響應(yīng)結(jié)果傳遞給JavaScript,。Flash URLLoader是一種很普遍的跨域解決方案,,不過需要支持iOS的話,這個(gè)方案就不可行了,。


四,、Access Control


此跨域方法目前只在很少的瀏覽器中得以支持,這些瀏覽器可以發(fā)送一個(gè)跨域的HTTP請(qǐng)求(Firefox, Google Chrome等通過XMLHTTPRequest實(shí)現(xiàn),,IE8下通過XDomainRequest實(shí)現(xiàn)),,請(qǐng)求的響應(yīng)必須包含一個(gè)Access- Control-Allow-Origin的HTTP響應(yīng)頭,該響應(yīng)頭聲明了請(qǐng)求域的可訪問權(quán)限,。例如baidu.com對(duì)google.com下的getUsers.php發(fā)送了一個(gè)跨域的HTTP請(qǐng)求(通過ajax),,那么getUsers.php必須加入如下的響應(yīng)頭:

header('Access-Control-Allow-Origin: http://www.baidu.com');//表示允許baidu.com跨域請(qǐng)求本文件

五、window.name


window 對(duì)象的name屬性是一個(gè)很特別的屬性,,當(dāng)該window的location變化,,然后重新加載,它的name屬性可以依然保持不變,。那么我們可以在頁面 A中用iframe加載其他域的頁面B,,而頁面B中用JavaScript把需要傳遞的數(shù)據(jù)賦值給window.name,iframe加載完成之后(iframe.onload),,頁面A修改iframe的地址,,將其變成同域的一個(gè)地址,然后就可以讀出iframe的window.name的值了(因?yàn)锳中的window.name和iframe中的window.name互相獨(dú)立的,,所以不能直接在A中獲取window.name,而要通過iframe獲取其window.name),。這個(gè)方式非常適合單向的數(shù)據(jù)請(qǐng)求,,而且協(xié)議簡(jiǎn)單、安全,。不會(huì)像JSONP那樣不做限制地執(zhí)行外部腳本,。


六,、服務(wù)器代理


在數(shù)據(jù)提供方?jīng)]有提供對(duì)JSONP協(xié)議或者 window.name協(xié)議的支持,也沒有對(duì)其它域開放訪問權(quán)限時(shí),,我們可以通過server proxy的方式來抓取數(shù)據(jù),。例如當(dāng)baidu.com域下的頁面需要請(qǐng)求google.com下的資源文件getUsers.php時(shí),直接發(fā)送一個(gè)指向 google.com/getUsers.php的Ajax請(qǐng)求肯定是會(huì)被瀏覽器阻止,。這時(shí),,我們?cè)赽aidu.com下配一個(gè)代理,然后把Ajax請(qǐng)求綁定到這個(gè)代理路徑下,,例如baidu.com/proxy/, 然后這個(gè)代理發(fā)送HTTP請(qǐng)求訪問google.com下的getUsers.php,,跨域的HTTP請(qǐng)求是在服務(wù)器端進(jìn)行的(服務(wù)器端沒有同源策略限制),客戶端并沒有產(chǎn)生跨域的Ajax請(qǐng)求,。這個(gè)跨域方式不需要和目標(biāo)資源簽訂協(xié)議,,帶有侵略性。


雙向跨域(兩個(gè)iframe之間或者兩個(gè)頁面之間,,一般用于獲取對(duì)方數(shù)據(jù),,document.domain方式還可以直接操作對(duì)方DOM)


七、document.domain(兩個(gè)iframe之間)


通過修改document的domain屬性,,我們可以在域和子域或者不同的子域之間通信,。同域策略認(rèn)為域和子域隸屬于不同的域,比如baidu.com和 youxi.baidu.com是不同的域,,這時(shí),,我們無法在baidu.com下的頁面中調(diào)用youxi.baidu.com中定義的JavaScript方法。但是當(dāng)我們把它們document的domain屬性都修改為baidu.com,,瀏覽器就會(huì)認(rèn)為它們處于同一個(gè)域下,,那么我們就可以互相獲取對(duì)方數(shù)據(jù)或者操作對(duì)方DOM了。


問題:

1,、安全性,,當(dāng)一個(gè)站點(diǎn)被攻擊后,另一個(gè)站點(diǎn)會(huì)引起安全漏洞,。

2,、如果一個(gè)頁面中引入多個(gè)iframe,要想能夠操作所有iframe,,必須都得設(shè)置相同domain,。


八、location.hash(兩個(gè)iframe之間),,又稱FIM,,F(xiàn)ragment Identitier Messaging的簡(jiǎn)寫


因?yàn)楦复翱诳梢詫?duì)iframe進(jìn)行URL讀寫,iframe也可以讀寫父窗口的URL,,URL有一部分被稱為hash,,就是#號(hào)及其后面的字符,,它一般用于瀏覽器錨點(diǎn)定位,Server端并不關(guān)心這部分,,應(yīng)該說HTTP請(qǐng)求過程中不會(huì)攜帶hash,,所以這部分的修改不會(huì)產(chǎn)生HTTP請(qǐng)求,但是會(huì)產(chǎn)生瀏覽器歷史記錄,。此方法的原理就是改變URL的hash部分來進(jìn)行雙向通信,。每個(gè)window通過改變其他 window的location來發(fā)送消息(由于兩個(gè)頁面不在同一個(gè)域下IE、Chrome不允許修改parent.location.hash的值,,所以要借助于父窗口域名下的一個(gè)代理iframe),,并通過監(jiān)聽自己的URL的變化來接收消息。這個(gè)方式的通信會(huì)造成一些不必要的瀏覽器歷史記錄,,而且有些瀏覽器不支持onhashchange事件,,需要輪詢來獲知URL的改變,最后,,這樣做也存在缺點(diǎn),,諸如數(shù)據(jù)直接暴露在了url中,數(shù)據(jù)容量和類型都有限等,。下面舉例說明:


假如父頁面是baidu.com/a.html,,iframe嵌入的頁面為google.com/b.html(此處省略了域名等url屬性),要實(shí)現(xiàn)此兩個(gè)頁面間的通信可以通過以下方法,。


1,、a.html傳送數(shù)據(jù)到b.html


(1) a.html下修改iframe的src為google.com/b.html#paco

(2) b.html監(jiān)聽到url發(fā)生變化,觸發(fā)相應(yīng)操作


2,、b.html傳送數(shù)據(jù)到a.html,,由于兩個(gè)頁面不在同一個(gè)域下IE、Chrome不允許修改parent.location.hash的值,,所以要借助于父窗口域名下的一個(gè)代理iframe


(1) b.html下創(chuàng)建一個(gè)隱藏的iframe,,此iframe的src是baidu.com域下的,并掛上要傳送的hash數(shù)據(jù),,如src='http://www.baidu.com/proxy.html#data'

(2) proxy.html監(jiān)聽到url發(fā)生變化,,修改a.html的url(因?yàn)閍.html和proxy.html同域,所以proxy.html可修改a.html的url hash)

(3) a.html監(jiān)聽到url發(fā)生變化,,觸發(fā)相應(yīng)操作


b.html頁面的關(guān)鍵代碼如下

try { parent.location.hash = 'data'; } catch (e) { // ie,、chrome的安全機(jī)制無法修改parent.location.hash, var ifrproxy = document.createElement('iframe'); ifrproxy.style.display = 'none'; ifrproxy.src = 'http://www.baidu.com/proxy.html#data'; document.body.appendChild(ifrproxy); }

proxy.html頁面的關(guān)鍵代碼如下

//因?yàn)閜arent.parent(即baidu.com/a.html)和baidu.com/proxy.html屬于同一個(gè)域,,所以可以改變其location.hash的值 parent.parent.location.hash = self.location.hash.substring(1);

九,、使用HTML5的postMessage方法(兩個(gè)iframe之間或者兩個(gè)頁面之間)


高級(jí)瀏覽器Internet Explorer 8 , chrome,F(xiàn)irefox , Opera  和 Safari 都將支持這個(gè)功能。這個(gè)功能主要包括接受信息的'message'事件和發(fā)送消息的'postMessage'方法,。比如baidu.com域的A頁面通過iframe嵌入了一個(gè)google.com域的B頁面,可以通過以下方法實(shí)現(xiàn)A和B的通信


A頁面通過postMessage方法發(fā)送消息:

window.onload = function() { var ifr = document.getElementById('ifr'); var targetOrigin = 'http://www.google.com'; ifr.contentWindow.postMessage('hello world!', targetOrigin); };

postMessage的使用方法:


otherWindow.postMessage(message, targetOrigin);


otherWindow:   指目標(biāo)窗口,,也就是給哪個(gè)window發(fā)消息,,是 window.frames 屬性的成員或者由 window.open 方法創(chuàng)建的窗口

message:   是要發(fā)送的消息,類型為 String,、Object (IE8,、9 不支持)

targetOrigin:   是限定消息接收范圍,不限制請(qǐng)使用 '*'


B頁面通過message事件監(jiān)聽并接受消息:

var onmessage = function (event) { var data = event.data;//消息 var origin = event.origin;//消息來源地址 var source = event.source;//源Window對(duì)象 if(origin=='http://www.baidu.com'){ console.log(data);//hello world! } }; if (typeof window.addEventListener != 'undefined') { window.addEventListener('message', onmessage, false); } else if (typeof window.attachEvent != 'undefined') { //for ie window.attachEvent('onmessage', onmessage); }
同理,,也可以B頁面發(fā)送消息,,然后A頁面監(jiān)聽并接受消息。


總結(jié)


跨域的方法很多,,不同的應(yīng)用場(chǎng)景我們都可以找到一個(gè)最合適的解決方案,。比如單向的數(shù)據(jù)請(qǐng)求,我們應(yīng)該優(yōu)先選擇JSONP或者window.name,,雙向通信優(yōu)先采取location.hash,,在未與數(shù)據(jù)提供方達(dá)成通信協(xié)議的情況下我們也可以用server proxy的方式來抓取數(shù)據(jù)。


相關(guān):【js跨域】js實(shí)現(xiàn)跨域訪問的幾種方式

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多