iframe詭異的內容消失問題

來源: 宅居  發布時間: 2011-01-20 23:54  閱讀: 5274 次  推薦: 0   原文鏈接   [收藏]  
摘要:該文章講解iframe詭異的內容消失問題,希望對您有所幫助。

  問題描述

  不得不承認,這是一個非常詭異的問題,以下步驟可以重現問題:

  1. 用IE打開這個測試頁面,確認頁面上有個iframe,里面顯示著abc三個字符。
  2. 把這頁面加進收藏夾。
  3. 重新打開IE。
  4. 從收藏夾再打開這頁面 。

  如果沒出問題的話,你會發現頁面上雖然還有iframe,但是abc消失了。更準確、詳細地說,前后2次的頁面主要有以下區別:

  • 從視覺上來說,頁面中的abc字符消失了。
  • 從DOM結構上看,iframe中的body元素內沒有任何內容。
  • 從iframe的右鍵-屬性上看,第一次頁面上iframe的地址是父頁面的URL,第二次則變成了about:blank。

  以下是這個頁面的源碼,是從遇上問題的頁面中不斷分離、簡化,最后形成的一個最簡的重現方案:

 
!DOCTYPE html
html
head
meta charset="utf-8" /
titletest/title
/head
body
script type="text/javascript"
var text = 'abc',
script
= 'var d = document; ' +
'd.open(\'text/html\', \'replace\'); d.write(parent.text); d.close();',
html = 'iframe id="abc" name="abc" ' +
'src="javascript:void((function() {' + script + '})())"/iframe';
document.write(html);

/script
/body
/html

  解決方案

  首先,這個頁面雖然簡單,但其中用到了幾個很惡心人的東西:

  • document.write。
  • javascript:偽協議。

  如果有辦法避免使用這兩者的話,就可以忽略這個問題。但是如果必須使用javascript:偽協議來向iframe中輸出內容的話,將以上代碼改為如下形式可以解決問題:

 
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
//插入到需要的位置
iframe.contentWindow.location = 'javascript:void((function() {' + script + '})())';

  具體的區別是,從直接使用document.write來輸出iframe,變為了使用createElement創建iframe,隨后使用iframe的location來采用javascript:偽協議輸出具體內容。

  起因

  由于原本這段代碼不是我寫的,所以在發現這個問題的時候,我也有過疑問,為啥要這么寫呢?難道下面的方式不是更好嗎:

 
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
//插入到需要的位置
iframe.contentWindow.document.write('abc');

  然而這一段代碼的注釋中寫是IE在修改了document.domain進行提權后,iframe會出現跨域問題。所以以下代碼,其中在IE中是會報錯(拒絕訪問)的:

 
//假設當前域是www.tt.com
document.domain = 'tt.com'; //domain提權
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
//插入到需要的位置
iframe.contentWindow.document.write('abc');

  至于解決的辦法,就是在iframe的src中,使用javascript:偽協議輸出內容,當然輸出的時候要注意,在iframe的document執行open以后,加上一句代碼,把iframe的docuemnt.domain也進行提權,提升到和父頁面相同,這樣iframe和父頁面就是同域的,可以進行交互了。

  正是因為IE存在著這樣的問題,為了解決這個問題,原有代碼中使用了document.write輸出帶src屬性的iframe元素,從而引發了另一個問題……

  猜測

  那么這個問題是因為什么原因引起的呢?首先對頁面的執行過程進行分析,大致是這么幾步:

  1. 解析script標簽,執行內容。
  2. document.write向文檔流中輸出一個iframe元素。
  3. iframe中,使用document.write輸出文字。

  從頁面的視覺效果而言,iframe是存在的,但iframe里面的內容消失了。這讓人很自然地聯想到,第2步已經執行了,但由于瀏覽器緩存iframe的內容等原因,第3步并沒有執行。

  為了測試這個情況,比較簡單的方法就是在iframe的src里的javascript代碼中添加一個斷點,我的選擇是在d.close()這一句之前,加上了一行代碼:alert(d.body.innerHTML);

  經過以上的修改,執行的結果是,成功地出現了alert對話框,并且innerHTML確實存在abc字符,另外更奇怪的是,經過alert,abc出現在了iframe中。

  也就是說,第3步是確實地執行了,但是在沒有alert的情況下,卻沒有在界面上產生任何效果。綜合以上的原因,聯想到alert函數的一個作用是將瀏覽器的UI Update隊列進行flush操作,因此對于完全黑盒的IE瀏覽器,現階段只能猜測,在這種特殊的使用方式之下,IE丟失了UI Update隊列中的部分更新,導致iframe的document并沒有得到更新,因此也保留了about:blank這種地址。

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()