Помилка JavaScript "Доступ заборонено" під час спроби отримати доступ до об'єкта документа програмно створеного <iframe> (лише для IE)


80

У мене є проект, в якому мені потрібно створити елемент <iframe> за допомогою JavaScript і додати його до DOM. Після цього мені потрібно вставити трохи вмісту в <iframe>. Це віджет, який буде вбудований на сторонні веб-сайти.

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

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

Це має певний сенс, оскільки я усвідомлюю, що Internet Explorer вимагає від вас встановити однакове значення для документа. Однак я не знаю жодного способу встановити це значення для документа, до якого я не можу отримати доступ.

Хтось знає про спосіб зробити це - якось встановити властивість 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'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>

Я приймав його за адресою:

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

Як ви побачите, якщо ви завантажите цю сторінку в IE, у той момент, коли я називаю alert (), я маю дескриптор на вікні об'єкта <iframe>; Я просто не можу заглибитися в об'єкт документа.

Щиро дякуємо за будь-яку допомогу чи пропозиції! Я буду в боргу тим, хто може допомогти мені знайти рішення цього.


Посилання для troy.onespot мертве.
mbomb007

Відповіді:


67

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

Зітхайте. Так, це проблема IE (помилка? Важко сказати, оскільки не існує документованого стандарту для такого роду неприємностей). Коли ви створюєте srcless iframe, він отримує a document.domainз батьківського документа location.hostзамість його document.domain. На той момент ви майже втратили, оскільки не можете змінити це.

srcЖахливим обхідним шляхом є встановлення JavaScript: URL (urgh!):

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

Але з якихось причин такий документ не може встановити свій власний document.domainсценарій в IE (стара стара "невизначена помилка"), тому ви не можете використовувати це, щоб відновити міст між батьківським (*). Ви можете використовувати його для написання цілого документа HTML, припускаючи, що віджету не потрібно спілкуватися з батьківським документом після його створення.

Однак URL-адреси iframe JavaScript не працюють у Safari, тож вам все одно знадобиться якийсь метод пошуку браузера, щоб вибрати, який метод використовувати.

*: З якоїсь іншої причини ви можете в IE встановити document.domainз другого документа, документ. Написаного першим документом. Отже, це працює:

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

На даний момент рівень мерзенності для мене занадто високий, я вийшов. Я б зробив зовнішній HTML, як сказав Девід.


10
@bobince: Ти чудовий! Я фактично натрапив на цей самий підхід пізно вчора ввечері після набагато більше гуглиння. Насправді, я думаю, що, можливо, я знайшов би ще більш надійне і потенційно менш важке крос-браузерне рішення: telerik.com/community/forums/aspnet-ajax/editor/… - зверніть увагу на пост Джеффа Таккера від 21 серпня. iframe> атрибут "src" до "javascript: void ((function () {document.open (); document.domain = \ 'tld.com \'; document.close ();}) ())" здається зробити трюк і в крос-браузерному режимі. Це також працює в Safari (принаймні v3 +).
Бангл

1
Ось тестова сторінка, що ілюструє мій попередній коментар: troy.onespot.com/static/access_denied_test.html
Бангл,

1
Чудово! Це набагато краще! Цікаво, що безпосереднє виконання цього повинно працювати ... як правило, javascript: URL-адреса буде виконуватися в контексті батьківського, але, схоже, це не так у випадку з iframe src. Можливо, ви також можете втратити void()дзвінок, оскільки функція вже повертається undefined.
bobince

1
Випадково ви отримуєте помилку при перезавантаженні сторінки в IE з цим, оскільки IE намагається зберегти розташування iframe ... argh. Не знаю, якщо є спосіб обійти це.
bobince

1
@bobince: О, чоловіче, ти маєш рацію. Дякую, що вказали на це; Я був настільки схвильований, що це спрацювало вперше, і я не потрудився перезавантажити. Що ви маєте на увазі під IE, який намагається зберегти розташування <iframe>? Я маю знайти рішення цього, тому буду тримати вас у курсі - будь-ласка, зробіть те ж саме, якщо випадково щось знайдете.
Бангл

18

Ну так, виняток доступу пов’язаний з тим фактом, який document.domainповинен збігатися у вашому батькові та вашому iframe, і перед тим, як вони це зроблять, ви не зможете програмно встановитиdocument.domain властивість вашого iframe.

Я думаю, що найкращим варіантом тут є вказати сторінку на власний шаблон:

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

І в myiframe.htm:

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

3
Дякую, Девід. Якщо я правильно розумію, шаблон повинен знаходитись в тому ж домені, що і батьківська сторінка (чи не так?), І це ускладнить впровадження для наших клієнтів. В ідеалі реалізація повинна бути такою ж простою, як вставлення кількох рядків JavaScript у HTML їх сторінок.
Бангл

1
Так, рішення вимагає іншого файлу саме в цьому домені. Я боюся, що це найкраще, що я можу придумати.
Девід Хедлунд,

1
@Bungle: Я думаю, це ваш єдиний варіант.
Тім Даун

3

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

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

зауважте, що я не можу встановити їх занадто foo.com b / c на сторінці є інший iframe, який вказує на bafoo.com (який знову використовує a.foo.com, але я не можу там змінити код сценарію)

Ви зауважите, що я по суті встановлюю document.domain на те, що він і так уже був би ... але я повинен це зробити, щоб отримати доступ до іншого iframe, про який я згадав з bafoo.com

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

є й інші речі, які справді бизарі

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

також, якщо я встановив все як foo.com (що, як я вже сказав, я не можу зробити), це працює! але з якихось причин при використанні того самого значення, що і location.host .... це не робить, і його несамовито вбиває мене .....


2

Я просто використовую, <iframe src="about:blank" ...></iframe>і це чудово працює.


2

для IE порт має значення. Між доменами це повинен бути той самий порт.


1

Ви пробували jQuery.contents () ?


1
Деніс, гарна пропозиція та спасибі - я зробив це (див. < Troy.onespot.com/static/access_denied_jquery.html> ), але отримав подібну помилку; на цей раз це "Дозвіл відмовлено" у сценарії jQuery. Я підозрюю, що це той самий чи подібний блокпост.
Бангл

1
На жаль, ця URL-адреса була зіпсована. Спробуйте: troy.onespot.com/static/access_denied_jquery.html
Бангл

4
Чому jQuery має магічний доступ до документа iframe?
Тім Даун

8
@Tim Down: Я не думаю, що припущенням було те, що jQuery матиме магічний доступ; швидше, у jQuery часто є кілька хитрих хитрощів для вирішення проблем між браузерами, і, можливо, він уже застосував обхідний шлях. Я згоден, що це не віщувало нічого доброго, але я вважаю, що це були хороші пропозиції та варті пострілу.
Бангл

Це справді не відповідь. Це лише пропозиція, і, мабуть, це буде краще як коментар до оригінального допису.
Ніл Монро

1

Здається, проблема з IE виникає при спробі отримати доступ до iframe через об'єкт document.frames - якщо ви зберігаєте посилання на створений iframe у змінній, тоді ви можете отримати доступ до вставленого iframe через змінну (my_iframe у коді нижче ).

Я отримав це для роботи в 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
Дякую. Здається, це вирішило проблему для мене.
віт

1
дивно, що це було те саме, що я використовував. працював нормально, тепер раптом я продовжую отримувати доступ до getttig, у якому заборонено помилки
frostymarvelous

1

У мене була подібна проблема, і моїм рішенням був цей фрагмент коду (протестовано в 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>');

Я спробував кілька методів, але цей виявився найкращим. Ви можете знайти кілька пояснень у моєму дописі в блозі тут .


1

Дотримуючись надзвичайно простого методу від 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");
   }
 });

-2

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 і отримав помилку в забороненому доступі в IE9.

З Провідника Windows

  • Я клацнув правою кнопкою миші на файлі, вибраному Властивості
  • Вибрав вкладку Безпека
  • Клацнув кнопку Додатково
  • Вибрано вкладку власника
  • Клацнув на кнопку Редагувати
  • Вибрані адміністратори (ім'я машини \ адміністратори)
  • Клацніть Застосувати
  • Закрив усі вікна.

Перевірив сайт. Більше немає.

Мені довелося зробити те ж саме для скрипта jQuery-UI, який я щойно оновив


2
Я думаю, ти вирішуєш іншу проблему.
Даніал Айтекін

5
OP створює сторонній віджет. Ви не можете очікувати, що кожен відвідувач виконає всі ці кроки, щоб відобразити віджет.
Крістоф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.