如何解決Asp.Net Ajax 1.0跨網域名稱架構情況下javascript“訪問拒絕”的問題[翻譯]

來源:互聯網
上載者:User
最近在使用Asp.Net Ajax1.0的架構,遇到了在不同網域名稱下拋出"Access dennied"異常的問題。在google上搜尋發現了該文章
How to work around the access denied cross-domain frame issue in ASP.NET Ajax 1.0

正好解決了我的問題,覺得作者分析的不錯,於是以我憋足的英語水平把它翻譯了,希望對學習Asp.Net Ajax的朋友用的上。

譯文如下:

如何解決Asp.Net Ajax 1.0跨網域名稱架構情況下javascript“訪問拒絕”的問題

     一些使用者可能已經遇到將Asp.net Ajax程式放在和最上層視窗網域名稱不一致的Frame或者Iframe中使用的情況。在IE瀏覽器中瀏覽這些網頁時,任何在架構中觸發的用戶端DOM事件(比如按一下滑鼠),IE將拋出“Access denied”(訪問拒絕)的異常。造成這種情況的原因是MicrosoftAjax.js中的Sys.UI.getLocation方法。其中有一段棘手的代碼,來擷取一個DOM元素相對於頁面左上方座標的像素值。所以Body下面的絕對位置的子項目使用這些座標,從而可以準確的代替你測量的元素。這個方法在滑鼠拖拽,快顯功能表的情境,比如自動完成。可以通過它擷取滑鼠相對於觸發滑鼠事件元素的座標。由於我們不能動態根據瀏覽器的相容性來決定不同瀏覽器的各自的行為,一次在Sys.UI.getLocation中的代碼正對不同瀏覽器做了特定的改寫。你僅僅需要知道,例如某瀏覽器不計算一個元素的scroll位置,當這個元素是Body的直接的子項目並且是絕對位置時。這就是我們需要解決的一種問題。幸運的是,IE有兩個方便的方法讓我們來完全繞過一些我們不能有效解決的Bug。getClientRects:擷取元素佔據頁面的所有矩形地區。getBoundingClientRect:返回一個包含整個元素的矩形地區。在我們使用的方法裡,我們已經使用了getClientRects方法,並且擷取到第一個矩形地區。因為我們需要一致化不同瀏覽器間的行為,即使對於一個封裝元素Span。這種情況下,元素的左上方就是包含該元素的第一個矩形地區的左上方,而不同於包含該元素的全域的矩形地區。如:

  
     這就是我們所犯的錯誤,不幸的是已經太晚了。getClientRects和getBoundingClientRect之間僅有一點點區別。區別在於,getClientRects在架構下使用時,給出的座標包含架構在最上層視窗中的位移值(offset 常常元素的offsetLeft offsetTop等屬性來描述)。然而getBoundingClientRect 直接給出不包括位移量的座標。兩個方法都需要包括計算Frameborder的高寬才能稱得上完美和準確。糾正getClientRects我們不得不去關注架構相對於最上層視窗的座標,並且減去它們,然而這種操作在跨網域名稱的架構下是被禁止的。

    解決辦法就是使用getBoundingClientRect來代替getClientRects,雖然在使用封裝元素(如span)情況下,這個辦法將在不同瀏覽器之間帶來一些不一致,但是總比徹底的失敗要好得多。新版本的函數依然需要使用try/catch來修正frameboder的問題,所以跨網域名稱架構的情況下,座標可能會有2個像素的偏差,但是這已經是最好的結果了。

解決問題的步驟

      首先,需要用外部的指令檔來代替編譯在Dll中基於資源的指令碼。通過設定ScriptManager的ScriptPath可以實現。外部的指令檔包可以在Microsoft Ajax Library ( http://ajax.asp.net/downloads/library/default.aspx?tabid=47&subtabid=471)找到,它是基於MSPL,你可以修改其中指令檔的內容。將Microsoft Ajax Library解壓縮後,拷貝檔案夾System.Web.Extensions到ScriptPath指定的位置。如果你不希望所有指令碼基於路徑被引用,你可以只指定核心指令檔MicrosoftAjax.js通過路徑引用,其他的指令檔繼續使用Web Resources的方式使用。這樣在使用其他基於資源的庫時要容易些,比如使用toolkit的時候。將下列指令碼加入到你的的Script Manager就可以輕鬆實現:

     當然,不要忘記將[Your Script Directory]替換成為你Web程式中對應的路徑。如果採用這種指令碼引用方式,不能在Script Manager中在設定ScriptPath了。完成上述步驟後,你可以檢查程式是否能繼續正常工作,並且使用網路監視工具比如Fidder來從新的路徑裝載指令碼。

     第二步就是要修複原來指令碼中的Bug了。我們需要修複指令碼的debug版本(MicrosoftAjax.debug.js)和發布版本。

     在MicrosoftAjax.debug.js找到以下代碼片斷

 

switch(Sys.Browser.agent) {
    case Sys.Browser.InternetExplorer:

    並且用下面的代碼替換介於“case Sys.Browser.Safari:”之間的所有代碼Sys.UI.DomElement.getLocation = function(element) {
    if (element.self || element.nodeType === 9) return new Sys.UI.Point(0,0);
    var clientRect = element.getBoundingClientRect();
    if (!clientRect) {
        return new Sys.UI.Point(0,0);
    }
    var ownerDocument = element.document.documentElement;
    var offsetX = clientRect.left - 2 + ownerDocument.scrollLeft,
        offsetY = clientRect.top - 2 + ownerDocument.scrollTop;
    
    try {
        var f = element.ownerDocument.parentWindow.frameElement || null;
        if (f) {
            var offset = 2 - (f.frameBorder || 1) * 2;
            offsetX += offset;
            offsetY += offset;
        }
    }
    catch(ex) {
    }    
    
    return new Sys.UI.Point(offsetX, offsetY);
}
break;

 

    對於發布版本(MicrosoftAjax.js),步驟基本相同,除了檔案有點難於操作以外(程式被搞成好長的幾行,要選中不太容易)。找到代碼片斷
"switch(Sys.Browser.agent){case Sys.Browser.InternetExplorer:”。並且用下面的代碼替換介於“case Sys.Browser.Safari:”之間的所有代碼
switch(Sys.Browser.agent){case Sys.Browser.InternetExplorer:Sys.UI.DomElement.getLocation=function(a){if(a.self||a.nodeType===9)return new Sys.UI.Point(0,0);var b=a.getBoundingClientRect();if(!b)return new Sys.UI.Point(0,0);var c=a.document.documentElement,d=b.left-2+c.scrollLeft,e=b.top-2+c.scrollTop;try{var g=a.ownerDocument.parentWindow.frameElement||null;if(g){var f=2-(g.frameBorder||1)*2;d+=f;e+=f}}catch(h){}return new Sys.UI.Point(d,e)};break;
    這個時候網站應該不會再拋出異常了

     這個修正帶來的已知後果

  • Sys.UI.DomElement.getLocation方法返回的座標,在不同網域名稱架構情境下將位移2像素
  • 這個修正執行結果返回元素邊界的左上方座標,代替了第一個包含當前元素的矩形地區的左上方,這樣對於封裝元素(span)是不同的。在不同瀏覽器下傳回值也不一致。

    重要免責聲明

     這項修正意味著你要停止使用基於資源的指令碼,而是用靜態檔案版本代替。我希望這個問題下次服務包發布時得到解決。所以當System.Web.Extensions發布新版本時,你將需要恢複到使用基於資源的指令碼使用方式,從而獲得其他問題的修正或者更新。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.