日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

记一次与iframe之间的抗争

發(fā)布時(shí)間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 记一次与iframe之间的抗争 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  iframe這個(gè)標(biāo)簽之前了解過(guò)這個(gè)東西,知道它可以引入外來(lái)的網(wǎng)頁(yè),但是實(shí)際開發(fā)中沒(méi)有用到過(guò)。這一次有一個(gè)需求是說(shuō)準(zhǔn)備要在網(wǎng)頁(yè)中嵌套另外一個(gè)網(wǎng)站,用iframe這個(gè)標(biāo)簽,讓我測(cè)試一下這個(gè)可不可以在自己的網(wǎng)頁(yè)中對(duì)引入進(jìn)來(lái)的iframe框架進(jìn)行操作,操作dom和css的一些東西。讓我做出一個(gè)小案例看看可不可以,我信誓旦旦保證說(shuō)可以的,我試過(guò)!!!

  就這樣交代給我之后信心滿滿的就開始了我的驗(yàn)證。

  什么是同源?

  同域名、 同端口、 同協(xié)議??

  網(wǎng)上是有好多這個(gè)的解釋的,給出一張圖片。 看下面這張圖片。 引用來(lái)自? 瀏覽器的同源策略

  

?

  我直接新建了一個(gè)文件夾,在里面寫了兩個(gè)html頁(yè)面的文件,舉例說(shuō)明是a.html和b.html,然后讓其中的一個(gè)a.html文件中用iframe標(biāo)簽的src去引入b.html文件,在里面去互相操作他們的css樣式和DOM元素。

  a.html

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><style>html,body{height: 100%;}body{background: pink;}#iframe1{width: 400px;height: 400px;margin: auto;background: blue;}</style> </head> <body>這里是父文檔 <input type="button" id="btn1" value="改變子文檔的顏色"> <input type="button" id="btn2" value="刪除span1"> <input type="button" id="btn3" value="改變span2的顏色"><input type="button" id="btn4" value="修改子文檔中的link標(biāo)簽"> <br /> <br /> <hr /> <iframe id="iframe1" src="b.html" frameborder="0"></iframe><script>// 只有同服務(wù)器下 同域名下才可以操作 不能更改別人的網(wǎng)頁(yè)。。var oBtn1 = document.getElementById('btn1');var oIframe1 = document.getElementById('iframe1');function fn(){document.body.style.background = 'green';}oBtn1.onclick = function () {console.log(oIframe1.contentWindow); // ---這個(gè)東西是子文檔中的window對(duì)象console.log(oIframe1.contentDocument); // ---- 這個(gè)東西是子文檔中的document對(duì)象oIframe1.contentWindow.document.body.style.background = 'yellow';};btn2.onclick = function () {var span1 =oIframe1.contentWindow.document.querySelector('.span1');console.log(span1);span1.parentNode.removeChild(span1);};btn3.onclick = function () {var span2 =oIframe1.contentWindow.document.querySelector('.span2');span2.style.color = 'red';};btn4.onclick = function () {var iFrameWindow = oIframe1.contentWindow;console.log(iFrameWindow.document.getElementsByTagName('link'));var link0 = iFrameWindow.document.getElementsByTagName('link')[0];console.log(link0.parentNode.removeChild(link0));}</script></body> </html>

?

b.html

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><style>body{background: yellowgreen;}</style><link rel="stylesheet" href="1.css"><link rel="stylesheet" href="2.css"> </head> <body><h1 id="h1">這里是子文檔1</h1><span class="span1">span1標(biāo)簽</span> <br><br><span class="span2">span2標(biāo)簽</span><span class="span3">span3標(biāo)簽</span><br /><hr /><input type="button" id="btn1" value="改變父文檔的顏色"><script>var oH1 = document.getElementById('h1');var oBtn1 = document.getElementById('btn1');oH1.onclick = function () {alert('子文檔中的點(diǎn)擊事件,我可以改變父文檔');console.log(window.parent); // -----這個(gè)parent對(duì)象是父文檔中的 window對(duì)象};oBtn1.onclick = function () {(function (window,document) {document.body.style.background = 'skyblue';})(window.parent, window.parent.document);};</script> </body> </html>

  樣式如下

?

上面的兩個(gè)代碼中用到了一個(gè)東西,在a.html文件中 用到了iframe標(biāo)簽元素的? .contentWindow.contentDocument 這兩個(gè)東西,它們兩個(gè)分別是子文檔也就是b.html中的window對(duì)象和document對(duì)象,那么你說(shuō)知道了這兩個(gè)東西要去操作它里面的東西還不簡(jiǎn)單嗎。

b.html文件中的? window.parent 這個(gè)東西是a.html的window對(duì)象,那么它同樣也可以去操作a.html中的元素了。所以交給我的任務(wù)我感覺(jué)完成了,就去問(wèn)他,這樣可以。然后我給他看了一下這個(gè)東西,后來(lái)了解到這兩個(gè)不是同一個(gè)域名下的,這兩個(gè)網(wǎng)站不是在一起的,然后我就回來(lái)又來(lái)調(diào)試。

?

不同端口下的調(diào)試

  我經(jīng)常用的編輯器是webstrom,它這個(gè)東西會(huì)自啟動(dòng)一個(gè) 127.0.0.1:63342的端口,我又用node做了一個(gè)簡(jiǎn)單的監(jiān)聽 3000端口的服務(wù)器,在網(wǎng)頁(yè)上面打開了。

  還是同樣的代碼吧,只不過(guò)把ifreme上面的src改為了我3000端口的網(wǎng)頁(yè)。

  

  但是這次瀏覽器給了我一個(gè)驚喜,因?yàn)槲腋杏X(jué)吧只有后端才會(huì)存在跨域什么的問(wèn)題,沒(méi)有想過(guò)前端的這些東西。

  它的打印出來(lái)的window對(duì)象都變了,好多都是false了,和之前在同一個(gè)頁(yè)面下面的東西都不一樣了~~

因?yàn)橐豢吹?origin? cross-origin就感覺(jué)是跨域的那種問(wèn)題。

  得了吧,去百度,google查到底怎么辦吧。我一直相信以我現(xiàn)在的水平遇到的問(wèn)題其他的人同樣也有人會(huì)遇到過(guò)。

  這一查不要緊,感覺(jué)看得好多文章開辟除了新的天地,真的是,在文章底部會(huì)給出參考文章,昨天我只看到了一種解決方案,并且將它付諸于實(shí)踐了,但是由于想要搞明白今天又找到了幾種解決方案,但是并沒(méi)有去試驗(yàn)。

  

  還是要講一講同源對(duì)哪些行為有限制?

  隨著互聯(lián)網(wǎng)的發(fā)展,同源策略 越來(lái)越嚴(yán)格。目前,如果非同源,共有三種行為受到限制。

  1. Cookie、localStorage和 IndexDB無(wú)法讀取

  2. DOM無(wú)法獲得

  3. AJAX 請(qǐng)求不能發(fā)送

  雖然這些限制是必要的,但是有時(shí)很不方便,合理的用途也會(huì)受到影響。

   

  這個(gè)問(wèn)題難道就沒(méi)有辦法解決了嗎?有的

  

Cookie解決方法

  Cookie 是服務(wù)器寫入瀏覽器的一小段信息,只有同源的網(wǎng)頁(yè)才能共享。但是,兩個(gè)網(wǎng)頁(yè)一級(jí)域名相同,只是二級(jí)域名不同,瀏覽器允許通過(guò)設(shè)置document.domain共享 Cookie。

  舉例來(lái)說(shuō),A網(wǎng)頁(yè)是http://w1.example.com/a.html,B網(wǎng)頁(yè)是http://w2.example.com/b.html,那么只要設(shè)置相同的document.domain,兩個(gè)網(wǎng)頁(yè)就可以共享Cookie。

  document.domain = 'example.com';

  現(xiàn)在,A網(wǎng)頁(yè)通過(guò)腳本設(shè)置一個(gè) Cookie。
  document.cookie = "test1=hello";

  B網(wǎng)頁(yè)就可以讀到這個(gè) Cookie。
  var allCookie = document.cookie;
  注意,這種方法只適用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 無(wú)法通過(guò)這種方法,規(guī)避同源政策,而要使用下文介紹的PostMessage API。

  另外,服務(wù)器也可以在設(shè)置Cookie的時(shí)候,指定Cookie的所屬域名為一級(jí)域名,比如.example.com。
  Set-Cookie: key=value; domain=.example.com; path=/
  這樣的話,二級(jí)域名和三級(jí)域名不用做任何設(shè)置,都可以讀取這個(gè)Cookie。

  上面這種方法暫時(shí)還沒(méi)有去試驗(yàn),等試驗(yàn)過(guò)后再來(lái)修改一下這里,因?yàn)樽约憾疾恢佬胁恍小?/p>

?

iframe

  如果兩個(gè)網(wǎng)頁(yè)不同源,就無(wú)法拿到對(duì)方的DOM,上面的第二個(gè)例子我已經(jīng)去試驗(yàn)過(guò)了,也看到報(bào)錯(cuò)信息了。

  就是父窗口運(yùn)行下面的命令,如果iframe窗口不是同源,就會(huì)報(bào)錯(cuò)。

document.getElementById("myIFrame").contentWindow.document // Uncaught DOMException: Blocked a frame from accessing a cross-origin frame.

  上面命令中,父窗口想獲取子窗口的DOM,因?yàn)榭缬蛸Y源導(dǎo)致報(bào)錯(cuò)。

  反之亦然,子窗口獲取主窗口的DOM也會(huì)報(bào)錯(cuò)。

window.parent.document.body // 報(bào)錯(cuò)

  前面講的這些實(shí)際上我第二個(gè)例子試驗(yàn)過(guò)了,下面也就是我遇到問(wèn)題的幾種解決方法。

  參考的他人的文章找到的,對(duì)于完全不同源的網(wǎng)站,目前有三種方法,來(lái)解決我遇到的問(wèn)題。

?

1. 片段標(biāo)識(shí)符

  片段標(biāo)識(shí)符呢也就是哈希值#,我們都知道當(dāng)網(wǎng)址資源#前面不變,后面的部分變化的時(shí)候網(wǎng)頁(yè)是不會(huì)刷新的,如果不清楚的話,可以看一下我之前寫過(guò)的一篇文章? 淺談SPA? ,里面有詳細(xì)的介紹#。

  就是父文檔和子文檔之間要交互時(shí),就去改變hash值 也就是#后面的部分,然后兩者再相互去監(jiān)聽hash變化的事件,再去自己做一些處理就好了

  

window.location.hash; // 這個(gè)是可以獲取hash值的window.onhashchange = function(){// 這個(gè)是hash值改變會(huì)觸發(fā)這個(gè)函數(shù) }

  舉一個(gè)小例子可以去試驗(yàn)一下

父窗口可以把信息,寫入到子窗口的片段標(biāo)識(shí)符

父窗口中的代碼

  

為了好看吧,就不用博客園自帶的那個(gè)代碼了,就這樣把子文檔的url地址給改變了吧,因?yàn)?不會(huì)刷新網(wǎng)頁(yè),而子文檔中也可以監(jiān)聽到這個(gè)#值的改變,所以子文檔中

瀏覽器中打印的東西

在這里可以看到了,我們傳遞過(guò)去的數(shù)據(jù)信息為 #changeColor,在子頁(yè)面中可以判斷#后面的帶的東西,再去執(zhí)行自己的邏輯。

?

同樣的子文檔給父文檔傳遞數(shù)據(jù)

  我們不是可以拿到父文檔的那個(gè) window.parent嗎,就用這個(gè)去改變就可以了,但是? BUT!!!

  我在子頁(yè)面中使用的時(shí)候

btn1.onclick = function () {console.log(parent.location); }

  

?這是什么嘛,你父文檔都可以改子文檔了,問(wèn)什么這個(gè)還是要 block frame with啥啥啥的,我本來(lái)以為可以成功的,這個(gè)有知道解決方法的大佬可以幫幫忙嗎。嘿嘿,暫時(shí)先這樣吧,父文檔已經(jīng)可以給子文檔傳遞信息了,我的解決方法也不是這種,暫時(shí)先把這個(gè)錯(cuò)誤問(wèn)題放一放,以后有解決方法了,會(huì)來(lái)這里修改的。

?

2. window.name

  瀏覽器窗口有window.name屬性,這個(gè)屬性最大的特點(diǎn)是,無(wú)論是否同源,只要在同一個(gè)窗口里面,前一個(gè)窗口設(shè)置了這個(gè)屬性后,后一個(gè)網(wǎng)頁(yè)可以讀取它。

  父窗口先打開一次子窗口,載入一個(gè)不同源的網(wǎng)頁(yè),將網(wǎng)頁(yè)信息寫入window.name屬性。

  

window.name = data;

  接著,子窗口跳回一個(gè)與主窗口同域的網(wǎng)址

location = 'http://parent.url.com/xxx.html'

  然后主窗口就可以讀取子窗口的window.name了

  

var data = document.getElementById('myFrame').contentWindow.name;

  這種方法的優(yōu)點(diǎn)是,window.name容量很大,可以放置非常長(zhǎng)的字符串;缺點(diǎn)是必須監(jiān)聽子窗口window.name屬性的變化,影響網(wǎng)頁(yè)性能。

3.跨文檔通信API? postMessage

?  我用到的解決方法是這種方法,感覺(jué)它和Vue之間的組件傳值一樣,不說(shuō)話了,直接上代碼,測(cè)試吧,記得那個(gè)子文檔是 3000端口的頁(yè)面

父文檔

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><style>body{background: pink;}#iframe1{width: 100%;height: 400px;}</style> </head> <body><input type="button" id="btn1" value="改變子文檔的東西"> <input type="button" id="btn2" value="刪除span1的顏色"> <input type="button" id="btn3" value="改變span2的顏色"> <br /> <hr /> <!--<iframe id="iframe1" src="http://localhost:3000" frameborder="0"></iframe>--> <iframe id="iframe1" src="http://localhost:3000" frameborder="0"></iframe> <script>var oIframe1 = document.getElementById('iframe1');var a = function fn(){document.body.style.background = 'green';};btn1.onclick = function () {console.log('傳遞的數(shù)據(jù)是','messageInfo');oIframe1.contentWindow.postMessage('changeColor',"http://localhost:3000");};btn2.onclick = function () {//oIframe1.contentWindow.postMessage('changeSpan2Color',"http://localhost:3000");oIframe1.contentWindow.postMessage('deleteSpan1',"http://localhost:3000")};btn3.onclick = function () {oIframe1.contentWindow.postMessage('changeSPan2Color',"http://localhost:3000")};window.addEventListener('message',function (res) {console.log(`這里是父文檔`);if(res.data == 'GetWhiteLabel')document.body.style.background = 'yellow';})</script> </body> </html>

  子文檔

<!doctype html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><style>body{background: skyblue;}</style> </head> <body><h1>這里是我的html頁(yè)面呢</h1><span class="span1">span1標(biāo)簽</span><span class="span2">span2標(biāo)簽</span> <br><input type="button" id="btn1" value="改變父文檔的東西"><script><!---->window.onload = function () {let parent = window.parent;window.addEventListener('message',function (res) {console.log(`******************這里是子頁(yè)面的接收到的消息*************`);console.log(res);switch (res.data) {case 'changeColor':document.body.style.background = 'green';break;case 'deleteSpan1':var oSpan1 = document.querySelector('.span1');oSpan1.parentNode.removeChild(oSpan1);break;case 'changeSPan2Color':var oSpan2 = document.querySelector('.span2');oSpan2.style.color = 'red';break;}});btn1.onclick = function () {parent.postMessage("GetWhiteLabel","*");}}</script> </body> </html>

  還是同樣的頁(yè)面吧,實(shí)現(xiàn)一樣的功能。

?

?上面有的地方寫的不太好,存在一些安全問(wèn)題,這個(gè)正是我現(xiàn)在正在做的地方,

oframe.contentWindow.postMessage(data,origin,false); //這個(gè)是postMessage的API // 發(fā)送的數(shù)據(jù) 子文檔地址 false// 在子文檔中去監(jiān)聽那個(gè)message的變化 window.addEventListener("message",function(res){console.log(res.data); //這個(gè)東西就是發(fā)送過(guò)去的數(shù)據(jù)// 去根據(jù)傳過(guò)來(lái)的不同的數(shù)據(jù) 再去做相應(yīng)的判斷 })

子文檔給父文檔傳數(shù)據(jù)的方式

parent.postMessage('message',origin,false); // 同樣也是類似的// 在父文檔中去監(jiān)聽那個(gè)message的值window.addEventListener("message",function(res){console.log(res.data); //這個(gè)東西就是發(fā)送過(guò)去的數(shù)據(jù)// 去根據(jù)傳過(guò)來(lái)的不同的數(shù)據(jù) 再去做相應(yīng)的判斷});

?這樣做可以實(shí)現(xiàn),就是有一些安全問(wèn)題,就是所有人如果查看你網(wǎng)站的源碼的話肯定會(huì)看到這個(gè)東西的,你寫的這么隨意,其他任何網(wǎng)站只要引入你的子文檔,然后就可以通過(guò)自己去寫一些東西去改變你的子文檔。

另外的一個(gè)缺點(diǎn)就感覺(jué)是 拓展性不好,你還需要去拿到子文檔的網(wǎng)站,還需要再去修改它的源代碼,感覺(jué)特別麻煩,如果有好幾十個(gè)頁(yè)面還要寫好幾十個(gè)嗎。

所以想到了一種傳值的方法,不穿那個(gè)要判斷的東西,把要修改的元素的html代碼的函數(shù)給傳過(guò)去,就是子文檔去定義一個(gè)接口去接收,父文檔把要執(zhí)行的事件都傳過(guò)去,然后子文檔寫一個(gè)執(zhí)行事件的接口。這里就會(huì)出現(xiàn)剛才第一個(gè)那個(gè)安全問(wèn)題了,更為嚴(yán)重,因?yàn)槟悴恢酪獔?zhí)行的是什么事件。

?

  現(xiàn)在有一個(gè)想法就是后臺(tái)做一個(gè)認(rèn)證,就像微信的那個(gè)access_token認(rèn)證一樣的東西,加密,每次去操作子文檔的時(shí)候,都要去請(qǐng)求,然后在子頁(yè)面監(jiān)聽到這個(gè)事件之后解密再兩個(gè)之間去對(duì)比,如果一樣了才去執(zhí)行,這個(gè)暫時(shí)還不知道如何去下手。

?

?  本文感覺(jué)特別有用的解決辦法和參考的文章有如下還有更多的沒(méi)有發(fā),如果你遇到了同樣的問(wèn)題,看了我的解決不了問(wèn)題,可以去看看下面的文章,當(dāng)然還可以給我留言,必回復(fù)。

  stackoverflow網(wǎng)頁(yè)中的問(wèn)答? ? ?博客園園友的文章 關(guān)于iframe的實(shí)踐? ? ?阮一峰大佬的? 瀏覽器同源政策及其規(guī)避方法

  

  如果有更好的解決辦法還望可以告知,謝謝!

  如果你閱讀了本文章有了一些收獲,我會(huì)感到非常開心,由于能力有限,文章有的部分解釋的不到位,希望在以后的日子里能慢慢提高自己能力,如果不足之處,還望指正。

轉(zhuǎn)載于:https://www.cnblogs.com/z937741304/p/9728160.html

總結(jié)

以上是生活随笔為你收集整理的记一次与iframe之间的抗争的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。