Lỗi JavaScript “Quyền truy cập bị từ chối” khi cố gắng truy cập đối tượng tài liệu của <iframe> được tạo lập trình (chỉ dành cho IE)


80

Tôi có dự án trong đó tôi cần tạo một phần tử <iframe> bằng JavaScript và nối nó vào DOM. Sau đó, tôi cần chèn một số nội dung vào <iframe>. Đó là một tiện ích sẽ được nhúng vào các trang web của bên thứ ba.

Tôi không đặt thuộc tính "src" của <iframe> vì tôi không muốn tải trang; thay vào đó, nó được sử dụng để cô lập / hộp cát nội dung mà tôi chèn vào đó để tôi không gặp xung đột CSS hoặc JavaScript với trang mẹ. Tôi đang sử dụng JSONP để tải một số nội dung HTML từ máy chủ và chèn nó vào <iframe> này.

Tôi có cách này hoạt động tốt, với một ngoại lệ nghiêm trọng - nếu thuộc tính document.domain được đặt trong trang mẹ (có thể nằm trong một số môi trường nhất định mà tiện ích này được triển khai), Internet Explorer (có thể là tất cả các phiên bản, nhưng tôi xác nhận trong 6, 7 và 8) mang lại cho tôi lỗi "Quyền truy cập bị từ chối" khi tôi cố gắng truy cập đối tượng tài liệu của <iframe> này mà tôi đã tạo. Nó không xảy ra trong bất kỳ trình duyệt nào khác mà tôi đã thử nghiệm (tất cả những trình duyệt hiện đại chính).

Điều này có ý nghĩa, vì tôi biết rằng Internet Explorer yêu cầu bạn đặt miền document.domain của tất cả các cửa sổ / khung sẽ giao tiếp với nhau thành cùng một giá trị. Tuy nhiên, tôi không biết bất kỳ cách nào để đặt giá trị này trên tài liệu mà tôi không thể truy cập.

Có ai biết cách thực hiện việc này không - bằng cách nào đó đặt thuộc tính document.domain của <iframe> được tạo động này? Hay tôi không nhìn nó từ góc độ phù hợp - có cách nào khác để đạt được những gì tôi đang làm mà không gặp phải vấn đề này không? Tôi cần phải sử dụng <iframe> trong mọi trường hợp, vì cửa sổ được tách biệt / hộp cát rất quan trọng đối với chức năng của tiện ích này.

Đây là mã thử nghiệm của tôi:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Document.domain Test</title>
    <script type="text/javascript">
      document.domain = 'onespot.com'; // set the page's document.domain
    </script>
  </head>
  <body>
    <p>This is a paragraph above the &lt;iframe&gt;.</p>
    <div id="placeholder"></div>
    <p>This is a paragraph below the &lt;iframe&gt;.</p>
    <script type="text/javascript">
      var iframe = document.createElement('iframe'), doc; // create <iframe> element
      document.getElementById('placeholder').appendChild(iframe); // append <iframe> element to the placeholder element
      setTimeout(function() { // set a timeout to give browsers a chance to recognize the <iframe>
        doc = iframe.contentWindow || iframe.contentDocument; // get a handle on the <iframe> document
        alert(doc);
        if (doc.document) { // HEREIN LIES THE PROBLEM
          doc = doc.document;
        }
        doc.body.innerHTML = '<h1>Hello!</h1>'; // add an element
      }, 10);
    </script>
  </body>
</html>

Tôi đã tổ chức nó tại:

http://troy.onespot.com/static/access_denied.html

Như bạn sẽ thấy nếu bạn tải trang này trong IE, tại thời điểm mà tôi gọi là alert (), tôi có xử lý đối tượng window của <iframe>; Tôi không thể đi sâu hơn vào đối tượng tài liệu của nó.

Cảm ơn rất nhiều cho bất kỳ sự giúp đỡ hoặc đề xuất! Tôi sẽ mang ơn bất cứ ai có thể giúp tôi tìm ra giải pháp cho việc này.


Liên kết cho troy.onespot đã chết.
mbomb007

Câu trả lời:


67

nếu thuộc tính document.domain được đặt trong trang mẹ, Internet Explorer sẽ cung cấp cho tôi thông báo "Quyền truy cập bị từ chối"

Thở dài. Vâng, đó là một vấn đề của IE (lỗi? Khó nói vì không có tài liệu tiêu chuẩn nào cho loại khó chịu này). Khi bạn tạo iframe không có src, nó nhận được một document.domaintừ tài liệu mẹ location.hostthay vì của nó document.domain. Tại thời điểm đó, bạn đã mất khá nhiều vì bạn không thể thay đổi nó.

Một giải pháp phức tạp là đặt thành srcjavascript: URL (urgh!):

 iframe.src= "javascript:'<html><body><p>Hello<\/p><script>do things;<\/script>'";

Nhưng vì lý do nào đó, tài liệu như vậy không thể đặt tài liệu riêng document.domaintừ tập lệnh trong IE ("lỗi không xác định"), vì vậy bạn không thể sử dụng tài liệu đó để lấy lại cầu nối giữa tài liệu gốc (*). Bạn có thể sử dụng nó để viết HTML toàn bộ tài liệu, giả sử rằng tiện ích con không cần phải nói chuyện với tài liệu mẹ của nó sau khi nó được khởi tạo.

Tuy nhiên, các URL JavaScript của iframe không hoạt động trong Safari, vì vậy bạn vẫn cần một số loại trình duyệt để chọn phương pháp sử dụng.

*: Vì một số lý do khác, bạn có thể , trong IE, đặt document.domaintừ tài liệu thứ hai, document. Được viết bởi tài liệu đầu tiên. Vì vậy, điều này hoạt động:

if (isIE)
    iframe.src= "javascript:'<script>window.onload=function(){document.write(\\'<script>document.domain=\\\""+document.domain+"\\\";<\\\\/script>\\');document.close();};<\/script>'";

Tại thời điểm này, mức độ gớm ghiếc là quá cao đối với tôi, tôi đã ra ngoài. Tôi sẽ làm HTML bên ngoài như David đã nói.


10
@bobince: Bạn thật tuyệt! Tôi thực sự đã tình cờ phát hiện ra cách tiếp cận này vào tối hôm qua sau khi tìm kiếm thêm trên Google. Trên thực tế, tôi nghĩ rằng tôi có thể đã tìm thấy một giải pháp trình duyệt chéo mạnh mẽ hơn và có khả năng ít khó khăn hơn: telerik.com/community/forums/aspnet-ajax/editor/… - lưu ý bài đăng của Jeff Tucker từ ngày 21 tháng 8. Đặt < thuộc tính "src" của iframe> thành "javascript: void ((function () {document.open (); document.domain = \ 'tld.com \'; document.close ();}) ())" dường như để thực hiện thủ thuật và theo cách trình duyệt chéo. Nó cũng hoạt động trong Safari (ít nhất là v3 +).
Bungle

1
Đây là trang thử nghiệm minh họa nhận xét trước đây của tôi: troy.onespot.com/static/access_denied_test.html
Bungle

1
Ôi tuyệt! Điều đó tốt hơn nhiều! Điều thú vị là làm điều đó trực tiếp sẽ hoạt động ... thông thường, một javascript: URL sẽ được thực thi trong ngữ cảnh gốc của nó, nhưng điều đó dường như không đúng với iframe src. Bạn cũng có thể bị mất void()cuộc gọi, vì hàm đã trả về undefined.
bobince

1
Tình cờ bạn gặp lỗi khi tải lại trang trong IE với điều này, vì IE cố gắng giữ lại vị trí iframe ... argh. Dunno nếu có một cách để giải quyết vấn đề đó.
bobince

1
@bobince: Ôi trời, bạn nói đúng. Cảm ơn vì đã chỉ ra điều đó; Tôi rất vui mừng vì nó hoạt động ngay lần đầu tiên mà tôi không buồn tải lại. Ý bạn là gì khi IE cố gắng giữ lại vị trí <iframe>? Tôi phải tìm ra giải pháp cho việc này nên tôi sẽ thông báo cho bạn - hãy làm như vậy nếu bạn tình cờ tìm thấy bất cứ điều gì.
Bungle

18

Vâng, ngoại lệ truy cập là do thực tế document.domainphải khớp trong nội tuyến gốc của bạn và iframe của bạn, và trước khi chúng khớp, bạn sẽ không thể đặt thuộc document.domaintính của iframe theo chương trình.

Tôi nghĩ lựa chọn tốt nhất của bạn ở đây là trỏ trang đến một mẫu của riêng bạn:

iframe.src = '/myiframe.htm#' + document.domain;

Và trong myiframe.htm:

document.domain = location.hash.substring(1);

3
Cảm ơn, David - tôi đánh giá cao những gì có vẻ là một gợi ý chắc chắn, nhưng tôi không muốn thực hiện cách tiếp cận này trừ khi đó là phương sách cuối cùng. Nếu tôi hiểu đúng, mẫu sẽ cần phải nằm trên cùng một miền với trang mẹ (đúng không?) Và điều đó sẽ làm phức tạp việc triển khai cho khách hàng của chúng tôi. Lý tưởng nhất là việc triển khai phải đơn giản như chèn một vài dòng JavaScript vào HTML của các trang của họ.
Bungle

1
Có, giải pháp yêu cầu một tệp khác trên chính miền đó. Tuy nhiên, tôi e rằng đó là điều tốt nhất mà tôi có thể nghĩ ra.
David Hedlund

1
@Bungle: Tôi nghĩ đó là lựa chọn duy nhất của bạn.
Tim Down

3

Tôi thực sự cũng gặp phải một vấn đề tương tự, nhưng có một sự thay đổi ... giả sử trang web cấp cao nhất là a.foo.com - bây giờ tôi đã đặt tên miền tài liệu thành a.foo.com

thì trong iframe mà tôi tạo / sở hữu, tôi cũng đặt nó a.foo.com

lưu ý rằng tôi không thể đặt chúng quá foo.com b / c có một iframe khác trong trang được trỏ đến bafoo.com (lại sử dụng a.foo.com nhưng tôi không thể thay đổi mã tập lệnh ở đó)

bạn sẽ lưu ý rằng về cơ bản, tôi đang đặt document.domain về những gì nó đã có sẵn ... nhưng tôi phải làm điều đó để truy cập iframe khác mà tôi đã đề cập từ bafoo.com

bên trong khung của tôi, sau khi tôi đặt miền, mặc dù tất cả các iframe đều có cùng cài đặt, tôi vẫn gặp lỗi khi liên hệ với phụ huynh trong IE 6/7

có những thứ khác mà tôi thực sự bizaree

ở cấp độ bên ngoài / cấp cao nhất, nếu tôi đợi sự kiện onload của nó và đặt bộ hẹn giờ, cuối cùng tôi có thể tiếp cận khung hình mà tôi cần truy cập .... nhưng tôi không bao giờ có thể tiếp cận từ dưới lên ... và tôi thực sự cần có khả năng

cũng như nếu tôi đặt mọi thứ là foo.com (như tôi đã nói tôi không thể làm) NÓ HOẠT ĐỘNG! nhưng vì một số lý do, khi sử dụng cùng một giá trị như location.host .... nó không và sự kỳ lạ của nó giết chết tôi .....


2

Tôi chỉ sử dụng <iframe src="about:blank" ...></iframe>và nó hoạt động tốt.


2

đối với IE, cổng quan trọng. Ở giữa các miền, nó phải là cùng một cổng.


1

Bạn đã thử jQuery.contents () chưa?


1
Deniss, gợi ý hay và cảm ơn bạn - Tôi đã thử điều này (xem < troy.onespot.com/static/access_denied_jquery.html> ) nhưng gặp lỗi tương tự; lần này là "Quyền bị từ chối" trong tập lệnh jQuery. Tôi nghi ngờ nó giống hoặc một rào cản tương tự.
Bungle

1
Xin lỗi, URL đó bị sai. Hãy thử: troy.onespot.com/static/access_denied_jquery.html
Bungle

4
Tại sao jQuery lại có quyền truy cập kỳ diệu vào tài liệu của iframe?
Tim Down

8
@Tim Down: Tôi không nghĩ giả định rằng jQuery sẽ có quyền truy cập kỳ diệu; thay vào đó, jQuery thường có một số thủ thuật tiện lợi để giải quyết các vấn đề trên nhiều trình duyệt và có thể đã triển khai một giải pháp thay thế. Tôi đồng ý rằng nó không có điềm báo tốt, nhưng tôi nghĩ đó là một gợi ý hay và đáng để thử.
Bungle

Đây thực sự không phải là một câu trả lời. Đó chỉ là một gợi ý và có lẽ sẽ tốt hơn khi nhận xét về bài đăng gốc.
Neil Monroe

1

Có vẻ như sự cố với IE xảy ra khi bạn thử và truy cập iframe thông qua đối tượng document.frames - nếu bạn lưu trữ một tham chiếu đến iframe đã tạo trong một biến thì bạn có thể truy cập iframe được chèn qua biến (my_iframe trong đoạn mã bên dưới ).

Tôi đã nhận được điều này để hoạt động trong IE6 / 7/8

var my_iframe;
var iframeId = "my_iframe_name"
if (navigator.userAgent.indexOf('MSIE') !== -1) {
  // IE wants the name attribute of the iframe set
  my_iframe = document.createElement('<iframe name="' + iframeId + '">');
} else {
  my_iframe = document.createElement('iframe');
}

iframe.setAttribute("src", "javascript:void(0);");
iframe.setAttribute("scrolling", "no");
iframe.setAttribute("frameBorder", "0");
iframe.setAttribute("name", iframeId);

var is = iframe.style;
is.border = is.width = is.height = "0px";

if (document.body) {
  document.body.appendChild(my_iframe);
} else {
  document.appendChild(my_iframe);
}

1
Cảm ơn. Điều này dường như đã khắc phục sự cố cho tôi.
vit

1
điều kỳ lạ là, đây cũng là thứ tôi đã sử dụng. đang hoạt động tốt, bây giờ đột nhiên, tôi tiếp tục truy cập getttig bị từ chối lỗi
frostymarvelous

1

Tôi đã gặp sự cố tương tự và giải pháp của tôi là đoạn mã này (được thử nghiệm trong IE8 / 9, Chrome và Firefox)

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);

iframe.src = 'javascript:void((function(){var script = document.createElement(\'script\');' +
  'script.innerHTML = "(function() {' +
  'document.open();document.domain=\'' + document.domain +
  '\';document.close();})();";' +
  'document.write("<head>" + script.outerHTML + "</head><body></body>");})())';

iframe.contentWindow.document.write('<div>foo</div>');

Tôi đã thử một số phương pháp nhưng phương pháp này có vẻ là tốt nhất. Bạn có thể tìm thấy một số giải thích trong bài đăng trên blog của tôi ở đây .


1

Làm theo phương pháp cực kỳ đơn giản từ Andralor tại đây đã khắc phục sự cố cho tôi: https://github.com/fancyapps/fancyBox/issues/766

Về cơ bản, hãy gọi lại iframe vào Ngày cập nhật:

$('a.js-fancybox-iframe').fancybox({
    type: 'iframe',
    scrolling : 'visible',
    autoHeight: true,
    onUpdate: function(){
     $("iframe.fancybox-iframe");
   }
 });

-2

IE hoạt động với iframe giống như tất cả các trình duyệt khác (ít nhất là đối với các chức năng chính). Bạn chỉ cần giữ một bộ quy tắc:

  • trước khi bạn tải bất kỳ javascript nào trong iframe (phần js cần biết về iframe cha), hãy đảm bảo rằng miền gốc đã thay đổi document.domain.
  • khi tất cả các tài nguyên iframe được tải, hãy thay đổi document.domain giống với tài nguyên được xác định trong cha. (Bạn cần thực hiện việc này sau vì việc đặt miền sẽ khiến yêu cầu của tài nguyên iframe không thành công)

  • bây giờ bạn có thể tạo tham chiếu cho cửa sổ mẹ: var winn = window.parent

  • bây giờ bạn có thể tạo tham chiếu đến HTML mẹ, để thao tác với nó: var parentContent = $ ('html', winn.document)
  • tại thời điểm này, bạn sẽ có quyền truy cập vào tài liệu / cửa sổ chính của IE và bạn có thể thay đổi nó khi bạn không muốn

-11

Đối với tôi, tôi thấy câu trả lời tốt hơn là kiểm tra các quyền của tệp mà quyền truy cập đang bị từ chối.

Tôi vừa cập nhật lên jQuery-1.8.0.js và gặp phải lỗi Access Denied trong IE9.

Từ Windows Explorer

  • Tôi nhấp chuột phải vào tệp đã chọn Thuộc tính
  • Đã chọn tab Bảo mật
  • Đã nhấp vào nút nâng cao
  • Đã chọn tab Chủ sở hữu
  • Đã nhấp vào nút Chỉnh sửa
  • Quản trị viên được Chọn (Tên máy \ Quản trị viên)
  • Đã nhấp vào Áp dụng
  • Đã đóng tất cả các cửa sổ.

Đã kiểm tra trang web. Không có vấn đề gì nữa.

Tôi cũng phải làm điều tương tự cho tập lệnh jQuery-UI mà tôi vừa cập nhật


2
Tôi nghĩ bạn đang giải quyết một vấn đề khác.
Danyal Aytekin 22/10/12

5
OP đang xây dựng một widget của bên thứ ba. Bạn không thể mong đợi mọi khách truy cập làm theo tất cả các bước này để hiển thị tiện ích con.
Christophe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.