Ошибка "Отказано в доступе" при попытке доступа к объекту документа программно созданного <iframe> (только для IE)

У меня есть проект, в котором мне нужно создать <iframe> элемент с использованием JavaScript и добавьте его в DOM. После этого мне нужно вставить некоторый контент в <iframe> . Это виджет, который будет встроен в сторонние веб-сайты.

Я не устанавливаю атрибут "src" в <iframe> так как я не хочу загружать страницу; скорее, он используется для изоляции/песочницы содержимого, которое я вставляю в него, чтобы я не сталкивался с конфликтами CSS или JavaScript с родительской страницей. Я использую JSONP для загрузки некоторого содержимого HTML с сервера и вставки его в этот <iframe> .

У меня есть это прекрасно, с одним серьезным исключением - если свойство document.domain установлено на родительской странице (которое может быть в определенных средах, в которых развертывается этот виджет), Internet Explorer (возможно, все версии, но Я подтвердил в 6, 7 и 8) дает мне ошибку "Доступ лишен", когда я пытаюсь получить доступ к объекту документа этого <iframe> Я создал. Это не происходит ни в каких других браузерах, которые я тестировал (все основные современные).

Это имеет смысл, так как я знаю, что Internet Explorer требует, чтобы вы установили document.domain из всех окон/фреймов, которые будут связываться друг с другом с тем же значением. Однако я не знаю, как установить это значение в документе, к которому я не могу получить доступ.

Кто-нибудь знает способ сделать это - как-то установить свойство document.domain этого динамически созданного <iframe> ? Или я не смотрю на него под прямым углом - есть ли другой способ добиться того, что я собираюсь, не столкнувшись с этой проблемой? Мне нужно использовать <iframe> в любом случае, поскольку изолированное/изолированное окно имеет решающее значение для функциональности этого виджета.

Здесь мой тестовый код:

<!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 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>

Я размещал его по адресу:

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

Как вы увидите, загрузите ли вы эту страницу в IE, в тот момент, когда я вызываю alert(), у меня есть дескриптор объекта window из <iframe> ;; Я просто не могу углубиться в объект документа.

Большое спасибо за любую помощь или предложения! Я буду обязан тем, кто может помочь мне найти решение.

Ответ 1

если свойство document.domain установлено на родительской странице, Internet Explorer дает мне "Доступ запрещен"

Вздох. Да, это проблема IE (ошибка трудно сказать, поскольку нет такого документального стандарта для такого рода неприятностей). Когда вы создаете srcless iframe, он получает document.domain из родительского документа location.host вместо своего document.domain. В этот момент вы сильно потеряли, так как не можете его изменить.

Ужасно обходным путем является установка src в javascript: URL (urgh!):

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

Но по какой-то причине такой документ не может установить свой собственный document.domain из script в IE (старая "неуказанная ошибка" ), поэтому вы не можете использовать это, чтобы восстановить мост между родителем ( *). Вы можете использовать его для написания всего документа HTML, считая, что виджет не должен разговаривать со своим родительским документом после его создания.

Однако URL-адреса iframe JavaScript не работают в Safari, поэтому вам все равно нужно какое-то представление об использовании браузера, чтобы выбрать, какой метод использовать.

*: По какой-то другой причине вы можете в IE установить document.domain из второго документа document.written первым документом. Итак, это работает:

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

В этот момент уровень отвратительности для меня слишком высок, я ухожу. Я бы сделал внешний HTML, как сказал Дэвид.

Ответ 2

Ну да, исключение доступа связано с тем, что document.domain должен совпадать с вашим родителем и вашим iframe, и до этого вы не сможете программно установить свойство document.domain вашего iframe.

Я думаю, что ваш лучший вариант здесь - указать страницу на собственный шаблон:

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

И в myiframe.htm:

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

Ответ 3

Ну, на самом деле у меня очень похожая проблема, но с твист... скажем, сайт верхнего уровня - a.foo.com - теперь я установил домен документа на сайт a.foo.com

то в iframe, который я создаю/владею, я также устанавливаю его. a.foo.com

Обратите внимание, что я не могу установить их слишком foo.com b/c есть еще один iframe на странице, указанной на bafoo.com(который снова использует a.foo.com, но я не могу изменить там код script)

Вы заметите, что im по существу установил document.domain на то, что он уже будет в любом случае... но я должен сделать это, чтобы получить доступ к другому iframe, упомянутому мной на b.a.foo.com

внутри моего фрейма после того, как я установил домен, хотя все фреймы имеют одинаковый параметр, я все равно получаю сообщение об ошибке при достижении родительского элемента в IE 6/7

есть и другие вещи, которые действительно bizaree

во внешнем/верхнем уровне, если я жду его события onload и устанавливаю таймер, в конце концов я могу дойти до кадра, в который мне нужно получить доступ.... но я никогда не могу достичь снизу вверх... и мне действительно нужно иметь возможность

также, если я установил все, чтобы быть foo.com(который, как я сказал, я не могу сделать) ЭТО РАБОТАЕТ! но по какой-то причине при использовании того же значения, что и location.host.... он не делает и его freaking убивает меня.....

Ответ 4

Я просто использую <iframe src="about:blank" ...></iframe>, и он отлично работает.

Ответ 5

для IE, порт имеет значение. Между доменами он должен быть одним и тем же портом.

Ответ 7

Кажется, что проблема с IE возникает, когда вы пытаетесь получить доступ к iframe через объект document.frames - если вы храните ссылку на созданный iframe в переменной, то вы можете получить доступ к введенному iframe через переменную (my_iframe in код ниже).

Я получил это, чтобы работать в 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);
}

Ответ 8

У меня была аналогичная проблема, и моим решением был этот фрагмент кода (протестирован в IE8/9, Chrome и 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>');

Я пробовал несколько методов, но этот оказался лучшим. Вы можете найти некоторые объяснения в своем сообщении в блоге здесь.

Ответ 9

Следуя чрезвычайно простому методу от Andralor, я решил проблему для меня: https://github.com/fancyapps/fancyBox/issues/766

По существу, снова вызовите iframe onUpdate:

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

Ответ 10

IE работает с iframe, как и все другие браузеры (по крайней мере, для основных функций). Вам просто нужно соблюдать набор правил:

  • перед загрузкой любого javascript в iframe (эта часть js, которая должна знать о родительском элементе iframe), убедитесь, что у родителя изменился document.domain.
  • когда загружаются все ресурсы iframe, измените document.domain таким же, как тот, который определен в родительском. (Вам нужно сделать это позже, потому что настройка домена приведет к сбою запроса ресурса iframe)

  • теперь вы можете сделать ссылку для родительского окна: var winn = window.parent

  • теперь вы можете сделать ссылку на родительский HTML, чтобы манипулировать им: var parentContent = $('html', winn.document)
  • В этот момент у вас должен быть доступ к родительскому окну/документу IE, и вы можете изменить его, как обычно,

Ответ 11

Для меня я нашел, что лучшим ответом было проверить разрешенные файлом разрешения доступа.

Я просто обновляю jQuery-1.8.0.js и получаю ошибку Access Denied в IE9.

Из проводника Windows

  • Я щелкнул правой кнопкой мыши по файлу, выбрав Свойства
  • Выбрал вкладку "Безопасность"
  • Нажмите кнопку "Дополнительно"
  • Выбран вкладка Владелец.
  • Нажмите кнопку "Изменить"
  • Выбранные администраторы (имя_каталога\администраторы)
  • Нажмите "Применить"
  • Закрыл все окна.

Протестировано сайт. Больше проблем.

Мне пришлось сделать то же самое для jQuery-UI script, который я только что обновил, а также