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找到以下代碼片斷
?



??? 并且用下面的代碼替換介于“
case Sys.Browser.Safari:
”之間的所有代碼

























?
對于發布版本(
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發布新版本時,你將需要恢復到使用基于資源的腳本使用方式,從而獲得其他問題的修正或者更新。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
