1. 程式人生 > >【原創】IE11驚現無厘頭Crash BUG(三招搞死你的IE11,並提供可重現代碼)!

【原創】IE11驚現無厘頭Crash BUG(三招搞死你的IE11,並提供可重現代碼)!

解決問題 html 窗口 前言 stat 錯誤 ont spa 環境

前言

很多人都知道我們在做FineUI控件庫,而且我們也做了超過 9 年的時間,在和瀏覽器無數次的交往中,也發現了多個瀏覽器自身的BUG,並公開出來方便大家查閱:

  • 分享IE7一個神奇的BUG(不是封閉標簽的問題,的確是IE7的BUG)
  • Chrome53 最新版驚現無厘頭卡死 BUG!
  • Chrome最新版(53-55)再次爆出BUG!

這類BUG之所以被大家所深惡痛絕,在於其隱蔽性,很多時候不能用常規的邏輯去分析。另一個原因的開發人員一般都很善良,出現問題總是從自身找原因,很少會懷疑到IDE,瀏覽器這些開發工具上面來。

事實情況是,瀏覽器也是開發人員開發的,是個軟件就有BUG!

今天公開的這個IE11的Crash BUG也郁悶了我好長時間,今天終於被我逮到了,哈哈哈哈......

發現問題

FineUI(專業版)其實在2016年3月就已經對桌面,平板和手機瀏覽器進行了適配,並且為手機瀏覽器增加了動畫效果(iOS下的Webkit和Andriod下的Chrome),但是這個CSS3動畫僅限於 WebKit 瀏覽器,並不支持Firefox,Edge,IE11等瀏覽器。

最近在版本更新中,我想把CSS3動畫效果擴展到桌面版的Firefox,Edge和IE11等瀏覽器,在開發過程中,突然有一天,我發現IE11只要打開調試工具(F12),瀏覽器就崩潰了,屢試不爽:

技術分享

IE11下打開頁面沒問題,但是只要F12打開調試工具,瀏覽器立馬Crash,點擊調試按鈕,出現的錯誤信息:

Unhandled exception at 0x754ED8D3 (KernelBase.dll) in iexplore.exe: 0xC0000005: Access violation writing location 0x08090FFC.

技術分享

貌似是內存寫入錯誤,對於純前端開發人員來說,遇到這樣的問題是一臉無奈:

技術分享

分析問題

幸運的是,上個版本的FineUI(專業版)沒有類似的問題,由於此時已經更新了很多代碼,所以下面就進入漫長的代碼比對階段。。。。

。。。。。

。。。。。

。。。。。

經過近一天的分析,問題集中在 CSS3 的 keyframes 關鍵字和 IFrame 一起使用時出現,我寫了兩個測試頁面:

test1.aspx:

<!DOCTYPE html>

<html>
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <f:PageManager ID="PageManager1" runat="server" />

        <iframe src="./test2.aspx"></iframe>
    </form>
</body>
</html>

test2.aspx

<!DOCTYPE html>

<html>
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <f:PageManager ID="PageManager1" runat="server" />

        <f:Button Text="按鈕" runat="server" />
    </form>
</body>
</html>

test2.aspx 生成的 HTML 代碼如下:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>

<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link type="text/css" rel="stylesheet" href="/res.axd?css=f.css&t=636364679643916663"/>
<link type="text/css" rel="stylesheet" href="/res.axd?css=themes.default.theme.css&t=636264594331716901"/>

<title>

</title></head>
<body>
    <form name="form1" method="post" action="test2.aspx" id="form1">
    
    。。。。。
    <div id="ctl02_wrapper" class="f-inline-block"></div>
    


<script type="text/javascript" src="/res.axd?js=f.js&t=636364680829342350"></script>
<script type="text/javascript" src="/res.axd?js=lang.zh_CN.js&t=636364679651261140"></script>


<script type="text/javascript">
//<![CDATA[
F.load(function () {
    F.f_init({
        theme: default,
        baseUrl : /,
        displayMode: normal,
        _version: 3.7.0,
        _customId: 0oOOoo
    });
    F.f_pagemanager = new F.Component({
        f_state: {},
        id: PageManager1,
        name: PageManager1,
        hidden: true
    });
    var f1 = new F.Button({
        f_state: {},
        id: ctl02,
        name: ctl02,
        renderTo: #ctl02_wrapper,
        text: 按鈕,
        handler: function () {
            F.f_disable(ctl02);
            __doPostBack(ctl02, ‘‘);
        }
    });
});//]]>
</script>
</form>
</body>
</html>

為了方便調試,我們把 test2.aspx 中引用的 CSS 文件下載下來,並更新 test2.aspx 為:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link type="text/css" rel="stylesheet" href="/res.axd?css=f.css&t=636364679643916663"/>

</head>
<body>

</body>
</html>

此時問題依舊,F12瀏覽器照樣Crash。遵循懷疑一切的原則,我們把 res.axd 加載的資源文件下載到本地 f.css,並把上面的 test2.aspx 改為:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link type="text/css" rel="stylesheet" href="f.css"/>

</head>
<body>

</body>
</html>

此時問題消失!!所以我們不得不懷疑 res.axd?css=f.css 和 f.css 的響應頭不一樣,因為兩者的內容完全相同。

事後看來這一懷疑是錯誤的,事後諸葛每個人都會做,但真正遇到類似的無厘頭BUG時,還是懷疑一切的好,我們甚至比較兩者的響應頭,唯一的不同是:

res.axd?css=f.css:

Content-Type:text/css; charset=utf-8

f.css:

Content-Type:text/css

然後,我們嘗試修改的 res.axd?css=f.css,使其和 f.css 的完全一樣,還是不行,瀏覽器照樣崩潰。

郁悶中....

此路不通

既然 res.axd?css=f.css 和 f.css 的響應頭完全相同,內容完全相同,但是效果卻截然不同,一個導致IE11崩潰,而另一個不會!

好吧,我們只好懷疑兩者的URL不同了,再來仔細對比下:

<link type="text/css" rel="stylesheet" href="/res.axd?css=f.css&t=636364679643916663"/>   (IE11打開調試工具時崩潰)

<link type="text/css" rel="stylesheet" href="f.css"/>   (IE11打開調試工具時不崩潰)

難道是。。。難道是。。。難道是。。。難道是。。。難道是。。。

一個最不可能的念頭在我腦海裏出現,難道是第一個URL太長了???

不要搞笑,這怎麽可能呢,Windows文件的路徑好像有長度限制,但,但,但,但,這個URL真的不長啊。。。。

不可能。。。算了。。。不是這個地方的問題。。。。

。。。。。

。。。。。

。。。。。

不行,還是把自己當個傻子,我就把URL改短一點,看是否有問題,我很坎坷的刪除了最後一個數字 3,把:

/res.axd?css=f.css&t=636364679643916663

改為:

/res.axd?css=f.css&t=63636467964391666

問題消失!!!!!

我都要驚呼了,難道真是URL太長了,還就多個一個字符!!!

一陣興奮之後,是一陣郁悶,因為我把URL加長了,同樣問題消失:

/res.axd?css=f.css&t=636364679643916663897978783784328467326473624763274632764732

再次思考

好吧,我是有點語無倫次,在經歷多次懷疑,否定,再懷疑,再否定之後,我們終於能夠重現問題了,其實很簡單:

IFrame中的這個CSS文件和父頁面中的CSS文件URL相同導致的(而不是URL長度的問題)!

至此,我們可以簡單的重現如下(下載可重現壓縮包,IE11打開後,F12直接崩潰):

test1.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link type="text/css" rel="stylesheet" href="fineui.css" />

</head>
<body>
    <iframe src="./test2.html"></iframe>
</body>
</html>

test2.html:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link type="text/css" rel="stylesheet" href="fineui.css" />

</head>
<body>

</body>
</html>

fineui.css:

@keyframes slideLeftIn {
    0% { opacity: 0; }
    100% { opacity: 1; }
}

在IE11中打開 test1.html,F12打開調試窗口,瀏覽器立馬崩潰!!!

技術分享

說好的《三招搞死你的IE11》

後來發現,這個問題不用 iframe 也能重現,只要滿足兩個條件,立馬崩潰:

  1. 頁面加載同一個CSS文件兩次
  2. CSS文件中包含 @keyframes 的定義

下面給出一個最簡單的測試例子(下載可重現壓縮包,IE11打開後,F12直接崩潰):

test3.html:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link type="text/css" rel="stylesheet" href="fineui.css" />
    <link type="text/css" rel="stylesheet" href="fineui.css" />

</head>
<body>

</body>
</html>

fineui.css

@keyframes slideLeftIn {
    0% { opacity: 0; }
    100% { opacity: 1; }
}

解決問題

暫無!

沒辦法,IE11自身的BUG,除非你不用IE11,或者繞行。

繞行有幾個簡單的辦法:

  1. CSS文件中不要包含 @keyframes 關鍵字(這個不可能,特別是希望IE11下支持CSS3動畫效果的)
  2. 不要在頁面中引用同一個CSS文件兩次(正確情況下沒人會引用兩次,而IFrame中就不可避免了!)
  3. 主頁面和IFrame中引用同一個CSS文件,給CSS文件加個隨機後綴(影響瀏覽器緩存,正式環境不建議用)

好吧,如果你真正需要 @keyframes 和 iframe 兩個元素時,還真沒辦法避免這個問題。

反饋

如果你用我們提供的《三步搞死你的IE11,瀏覽器打開後,F12直接崩潰》附件,能夠本機重現,請評論提供如下信息:

1. 操作系統版本

2. IE11版本

【原創】IE11驚現無厘頭Crash BUG(三招搞死你的IE11,並提供可重現代碼)!