小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

JS-iframe-跨窗口通訊

 Coder編程 2021-09-16

備注:補(bǔ)充一個(gè)額外方案:建立一個(gè)中間頁(yè)面,使子窗口跳轉(zhuǎn)到和主窗口同域的頁(yè)面中,再使用子窗口的parent操作父窗口。

 

跨窗口通訊

 

“相同來(lái)源”(相同站點(diǎn))策略限制了窗口和框架之間的訪問(wèn)。

這樣的想法是,如果用戶打開(kāi)了兩個(gè)頁(yè)面:一個(gè)來(lái)自john-smith.com,而另一個(gè)打開(kāi)gmail.com,則他們將不需要腳本來(lái)john-smith.com從中讀取我們的郵件gmail.com。因此,“相同來(lái)源”策略的目的是保護(hù)用戶免遭信息盜竊。

同源

如果兩個(gè)URL具有相同的協(xié)議,域和端口,則稱它們具有“相同的來(lái)源”。

這些URL都具有相同的來(lái)源:

  • http://
  • http:///
  • http:///my/page.html

這些沒(méi)有:

  • http://www.(另一個(gè)領(lǐng)域:www.重要)
  • http://site.org(另一個(gè)領(lǐng)域:.org重要)
  • https://(另一種協(xié)議:https
  • http://:8080(另一個(gè)端口:8080

“相同來(lái)源”政策規(guī)定:

  • 如果我們引用了另一個(gè)窗口,例如由創(chuàng)建的彈出window.open窗口或內(nèi)部的一個(gè)窗口<iframe>,并且該窗口來(lái)自同一原點(diǎn),則可以完全訪問(wèn)該窗口。
  • 否則,如果它來(lái)自另一個(gè)來(lái)源,那么我們將無(wú)法訪問(wèn)該窗口的內(nèi)容:變量,文檔等。唯一的例外是location:我們可以更改它(從而重定向用戶)。但是我們無(wú)法讀取位置(因此我們無(wú)法看到用戶現(xiàn)在所在的位置,也不會(huì)泄漏任何信息)。

實(shí)際應(yīng)用中:iframe

一個(gè)<iframe>標(biāo)簽主機(jī)單獨(dú)的嵌入式窗口,有自己的獨(dú)立documentwindow對(duì)象。

我們可以使用屬性訪問(wèn)它們:

  • iframe.contentWindow使窗戶進(jìn)入窗戶<iframe>。
  • iframe.contentDocument將文檔放入的<iframe>簡(jiǎn)寫iframe.contentWindow.document。

當(dāng)我們?cè)L問(wèn)嵌入式窗口內(nèi)的內(nèi)容時(shí),瀏覽器會(huì)檢查iframe的來(lái)源是否相同。如果不是這樣,則訪問(wèn)被拒絕(寫入location是一個(gè)例外,它仍然被允許)。

例如,讓我們嘗試<iframe>從另一個(gè)來(lái)源進(jìn)行讀寫

 
<iframe src="https://" id="iframe"></iframe>

<script>
  iframe.onload = function() {
    // we can get the reference to the inner window
    let iframeWindow = iframe.contentWindow; // OK
    try {
      // ...but not to the document inside it
      let doc = iframe.contentDocument; // ERROR
    } catch(e) {
      alert(e); // Security Error (another origin)
    }

    // also we can't READ the URL of the page in iframe
    try {
      // Can't read URL from the Location object
      let href = iframe.contentWindow.location.href; // ERROR
    } catch(e) {
      alert(e); // Security Error
    }

    // ...we can WRITE into location (and thus load something else into the iframe)!
    iframe.contentWindow.location = '/'; // OK

    iframe.onload = null; // clear the handler, not to run it after the location change
  };
</script>

上面的代碼顯示了除以下各項(xiàng)以外的所有操作的錯(cuò)誤:

  • 獲取對(duì)內(nèi)部窗口的引用iframe.contentWindow-允許的。
  • 寫信給location。

與此相反,如果<iframe>起源相同,我們可以使用它做任何事情:

 
<!-- iframe from the same site -->
<iframe src="/" id="iframe"></iframe>

<script>
  iframe.onload = function() {
    // just do anything
    iframe.contentDocument.body.prepend("Hello, world!");
  };
</script>
iframe.onload 與 iframe.contentWindow.onload

iframe.onload(在事件<iframe>標(biāo)簽)是基本上相同iframe.contentWindow.onload(在嵌入窗口對(duì)象)。當(dāng)嵌入式窗口完全加載所有資源時(shí)觸發(fā)。

…但是我們無(wú)法iframe.contentWindow.onload從其他來(lái)源訪問(wèn)iframe,因此請(qǐng)使用iframe.onload。

Windows在子域上:document.domain

根據(jù)定義,兩個(gè)具有不同域的URL具有不同的來(lái)源。

但是,如果窗口共享同一個(gè)二級(jí)域名,例如john.peter.(使他們共同的二級(jí)域名),我們可以讓瀏覽器忽略這種差別,使他們能夠從“同根同源”來(lái)對(duì)待為了跨窗口交流的目的。

為了使其正常工作,每個(gè)這樣的窗口都應(yīng)運(yùn)行以下代碼:

document.domain = '';

就這樣。現(xiàn)在,他們可以不受限制地進(jìn)行交互。同樣,這僅適用于具有相同二級(jí)域的頁(yè)面。

iframe:錯(cuò)誤的文檔陷阱

當(dāng)iframe來(lái)自同一來(lái)源時(shí),我們可能會(huì)訪問(wèn)它 document,這是一個(gè)陷阱。它與跨源事物無(wú)關(guān),但重要的是要知道。

創(chuàng)建后,iframe會(huì)立即擁有一個(gè)文檔。但是該文檔不同于加載到其中的文檔!

因此,如果我們立即對(duì)文檔進(jìn)行操作,則可能會(huì)丟失。

在這里,看看:

 
<iframe src="/" id="iframe"></iframe>

<script>
  let oldDoc = iframe.contentDocument;
  iframe.onload = function() {
    let newDoc = iframe.contentDocument;
    // the loaded document is not the same as initial!
    alert(oldDoc == newDoc); // false
  };
</script>

我們不應(yīng)該處理尚未加載的iframe的文檔,因?yàn)槟鞘?/span>錯(cuò)誤的文檔。如果我們?cè)谄渖显O(shè)置了任何事件處理程序,它們將被忽略。

如何檢測(cè)文檔在那里的時(shí)刻?

iframe.onload 觸發(fā)時(shí),正確的文檔肯定存在但是,只有在加載了所有資源的整個(gè)iframe時(shí),它才會(huì)觸發(fā)。

我們可以嘗試使用check in來(lái)趕上這一時(shí)刻setInterval

 
<iframe src="/" id="iframe"></iframe>

<script>
  let oldDoc = iframe.contentDocument;

  // every 100 ms check if the document is the new one
  let timer = setInterval(() => {
    let newDoc = iframe.contentDocument;
    if (newDoc == oldDoc) return;

    alert("New document is here!");

    clearInterval(timer); // cancel setInterval, don't need it any more
  }, 100);
</script>

集合:window.frames

獲取–的窗口對(duì)象的另一種方法<iframe>是從命名集合中獲取它 window.frames

  • 按編號(hào):window.frames[0]–文檔中第一幀的窗口對(duì)象。
  • 按名稱:window.frames.iframeName–具有的框架的窗口對(duì)象 name="iframeName"。

例如:

 
<iframe src="/" style="height:80px" name="win" id="iframe"></iframe>

<script>
  alert(iframe.contentWindow == frames[0]); // true
  alert(iframe.contentWindow == frames.win); // true
</script>

一個(gè)iframe可能內(nèi)部還有其他iframe。相應(yīng)的window對(duì)象形成層次結(jié)構(gòu)。

導(dǎo)航鏈接為:

  • window.frames –“子級(jí)”窗口的集合(用于嵌套框架)。
  • window.parent –對(duì)“父”(外部)窗口的引用。
  • window.top –對(duì)最頂層父窗口的引用。

例如:

 
window.frames[0].parent === window; // true

我們可以使用該top屬性來(lái)檢查當(dāng)前文檔是否在框架內(nèi)打開(kāi):

 
if (window == top) { // current window == window.top?
  alert('The script is in the topmost window, not in a frame');
} else {
  alert('The script runs in a frame!');
}

“沙盒” iframe屬性

sandbox屬性允許排除<iframe>in 內(nèi)部的某些操作,以防止其執(zhí)行不受信任的代碼。它通過(guò)將iframe視為來(lái)自其他來(lái)源和/或應(yīng)用其他限制來(lái)對(duì)其進(jìn)行“沙盒化”。

有適用于的“默認(rèn)設(shè)置”限制<iframe sandbox src="...">但是,如果我們提供一個(gè)以空格分隔的限制列表,可以將其放寬,這些限制不應(yīng)用作屬性的值,例如:<iframe sandbox="allow-forms allow-popups">。

換句話說(shuō),空"sandbox"屬性會(huì)施加最嚴(yán)格的限制,但我們可以放置一個(gè)用空格分隔的列表,以列出要?jiǎng)h除的屬性。

以下是限制的列表:

allow-same-origin
默認(rèn)情況下"sandbox",對(duì)iframe強(qiáng)制實(shí)施“不同來(lái)源”策略。換句話說(shuō),它使瀏覽器將iframe視為來(lái)自另一個(gè)來(lái)源,即使其src指向同一站點(diǎn)也是如此。具有所有隱含的腳本限制。此選項(xiàng)將刪除該功能。
allow-top-navigation
允許iframe更改parent.location。
allow-forms
允許提交來(lái)自的表格iframe。
allow-scripts
允許從運(yùn)行腳本iframe。
allow-popups
允許從window.open彈出窗口iframe

有關(guān)更多信息,請(qǐng)參見(jiàn)手冊(cè)。

以下示例演示了具有默認(rèn)限制集的沙盒iframe <iframe sandbox src="...">。它具有一些JavaScript和一種形式。

請(qǐng)注意,沒(méi)有任何效果。因此,默認(rèn)設(shè)置確實(shí)很苛刻:

結(jié)果
index.html
sandboxed.html
 
請(qǐng)注意:

"sandbox"屬性的目的只是添加更多限制。它無(wú)法刪除它們。特別是,如果iframe來(lái)自其他來(lái)源,則無(wú)法放寬同源限制。

跨窗口消息傳遞

postMessage界面允許Windows彼此交談,無(wú)論它們來(lái)自哪個(gè)來(lái)源。

因此,這是解決“相同來(lái)源”政策的一種方法。它允許從窗口john-smith.com進(jìn)行對(duì)話gmail.com和交換信息,但前提是它們都同意并調(diào)用相應(yīng)的JavaScript函數(shù)。這對(duì)用戶來(lái)說(shuō)很安全。

該界面分為兩個(gè)部分。

postMessage

想要發(fā)送消息的窗口調(diào)用接收窗口的postMessage方法。換句話說(shuō),如果要將消息發(fā)送到win,則應(yīng)致電 win.postMessage(data, targetOrigin)。

參數(shù):

data
要發(fā)送的數(shù)據(jù)。可以是任何對(duì)象,可以使用“結(jié)構(gòu)化序列化算法”克隆數(shù)據(jù)。IE僅支持字符串,因此我們應(yīng)該使用JSON.stringify復(fù)雜的對(duì)象來(lái)支持該瀏覽器。
targetOrigin
指定目標(biāo)窗口的原點(diǎn),以便只有給定原點(diǎn)的窗口才能獲取消息。

targetOrigin是一項(xiàng)安全措施。請(qǐng)記住,如果目標(biāo)窗口來(lái)自另一個(gè)來(lái)源,我們將無(wú)法location在發(fā)送方窗口中讀取它因此,我們不能確定現(xiàn)在正在預(yù)期的窗口中打開(kāi)了哪個(gè)站點(diǎn):用戶可以導(dǎo)航離開(kāi),并且發(fā)件人窗口對(duì)此一無(wú)所知。

指定該選項(xiàng)targetOrigin可確保窗口僅在正確位置時(shí)才接收數(shù)據(jù)。當(dāng)數(shù)據(jù)敏感時(shí)很重要。

例如,win僅在源頭有文檔的情況下,此處才接收消息http://

<iframe src="http://" name="example">

<script>
  let win = window.frames.example;

  win.postMessage("message", "http://");
</script>

如果我們不想檢查,可以將其設(shè)置targetOrigin*。

<iframe src="http://" name="example">

<script>
  let win = window.frames.example;

  win.postMessage("message", "*");
</script>

消息

要接收消息,目標(biāo)窗口應(yīng)具有message事件處理程序。觸發(fā)何時(shí)postMessage調(diào)用(并targetOrigin檢查成功)。

事件對(duì)象具有特殊的屬性:

data
來(lái)自的數(shù)據(jù)postMessage。
origin
例如,發(fā)件人的來(lái)源http://。
source
對(duì)發(fā)件人窗口的引用。source.postMessage(...)如果需要,我們可以立即返回。

要分配該處理程序,我們應(yīng)該使用addEventListener,短語(yǔ)法window.onmessage不起作用。

這是一個(gè)例子:

window.addEventListener("message", function(event) {
  if (event.origin != 'http://') {
    // something from an unknown domain, let's ignore it
    return;
  }

  alert( "received: " + event.data );

  // can message back using event.source.postMessage(...)
});

完整的例子:

結(jié)果
iframe.html
index.html
 

概要

要調(diào)用方法并訪問(wèn)另一個(gè)窗口的內(nèi)容,我們應(yīng)該首先對(duì)其進(jìn)行引用。

對(duì)于彈出窗口,我們有以下參考:

  • 在打開(kāi)器窗口中:window.open–打開(kāi)一個(gè)新窗口并返回對(duì)該窗口的引用,
  • 從彈出窗口:window.opener–是對(duì)彈出窗口中打開(kāi)器窗口的引用。

對(duì)于iframe,我們可以使用以下方法訪問(wèn)父/子窗口:

  • window.frames –嵌套窗口對(duì)象的集合,
  • window.parent,window.top是對(duì)父窗口和頂部窗口的引用,
  • iframe.contentWindow<iframe>標(biāo)簽內(nèi)的窗口。

如果Windows共享相同的來(lái)源(主機(jī),端口,協(xié)議),則Windows可以相互執(zhí)行任何操作。

否則,只有可能的操作是:

  • 更改location另一個(gè)窗口的(只讀訪問(wèn))。
  • 向其發(fā)布消息。

例外是:

  • 共享相同二級(jí)域的Windows:a.b.。然后document.domain=''將它們都設(shè)置為“原點(diǎn)相同”狀態(tài)。
  • 如果iframe具有sandbox屬性,則除非allow-same-origin該屬性值中指定,否則它將被強(qiáng)制置于“其他來(lái)源”狀態(tài)這可用于在同一站點(diǎn)的iframe中運(yùn)行不受信任的代碼。

postMessage界面允許兩個(gè)具有任何起源的窗口進(jìn)行交談:

  1. 發(fā)件人呼叫targetWin.postMessage(data, targetOrigin)。

  2. 如果targetOrigin不是'*',則瀏覽器檢查window targetWin是否具有原點(diǎn)targetOrigin。

  3. 如果是這樣,則使用特殊屬性targetWin觸發(fā)message事件:

    • origin–發(fā)送者窗口的來(lái)源(如http://my.
    • source –對(duì)發(fā)件人窗口的引用。
    • data –數(shù)據(jù),除IE僅支持字符串的任何地方的任何對(duì)象。

    我們應(yīng)該使用addEventListener它在目標(biāo)窗口內(nèi)設(shè)置此事件的處理程序。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(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)論公約

    類似文章 更多