“访问被拒绝”尝试访问以编程方式创建的<iframe>(仅限IE)</iframe>的文档对象时出现JavaScript错误

时间:2009-12-11 08:07:57

标签: javascript internet-explorer dom iframe document

我有项目,我需要创建一个&lt; iframe&gt;使用JavaScript的元素并将其附加到DOM。之后,我需要在&lt; iframe&gt;中插入一些内容。这是一个嵌入第三方网站的小部件。

我没有设置&lt; iframe&gt;的“src”属性因为我不想加载页面;相反,它用于隔离/沙箱插入我插入的内容,以便我不会遇到CSS或JavaScript与父页面冲突。我正在使用JSONP从服务器加载一些HTML内容并将其插入此&lt; iframe&gt ;.

我有这个工作正常,有一个严重的例外 - 如果在父页面中设置document.domain属性(它可能在部署此小部件的某些环境中),Internet Explorer(可能是所有版本,但是我在6,7和8中确认了当我尝试访问此&lt; iframe&gt;的文档对象时,给我一个“访问被拒绝”错误我创造了。它不会在我测试的任何其他浏览器中发生(所有主要的现代浏览器)。

这是有道理的,因为我知道Internet Explorer要求您将所有窗口/框架的document.domain设置为相互通信的相同值。但是,我不知道如何在我无法访问的文档上设置此值。

是否有人知道这样做的方法 - 以某种方式设置此动态创建的&lt; iframe&gt ;?的document.domain属性或者我不是从正确的角度看待它 - 有没有另一种方法可以实现我的目标而不会遇到这个问题?我需要使用&lt; iframe&gt;无论如何,隔离/沙盒窗口对于这个小部件的功能至关重要。

这是我的测试代码:

<!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()的时候,我确实有一个关于&lt; iframe&gt;的窗口对象的句柄;我只是无法深入到其文档对象中。

非常感谢您的任何帮助或建议!我非常感谢能帮助我找到解决方案的人。

11 个答案:

答案 0 :(得分:64)

  

如果在父页面中设置了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>'";

但由于某种原因,这样的文档无法在IE中设置自己的document.domain脚本(旧的“未指定的错误”),因此您无法使用它来重新获得父级之间的桥梁( *)。您可以使用它来编写整个文档HTML,假设小部件在实例化后不需要与其父文档通信。

但是,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。

答案 1 :(得分:18)

是的,访问异常是由于document.domain必须在您的父级和您的iframe中匹配,在此之前,您将无法以编程方式设置document.domain属性你的iframe。

我认为您最好的选择是将页面指向您自己的模板:

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

在myiframe.htm中:

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

答案 2 :(得分:3)

实际上我确实有一个非常类似的问题,但有一个扭曲... 说顶级网站是a.foo.com - 现在我将文档域设置为a.foo.com

然后在我创建/拥有的iframe中,我也将它设置为a.foo.com

请注意,我无法设置它们foo.com b / c页面中有另一个iframe指向bafoo.com(它再次使用a.foo.com但我无法更改脚本代码)

你会注意到我基本上将document.domain设置为它已经存在的东西......但我必须这样做以访问我从b.a.foo.com提到的其他iframe

在我的框架内,在我设置了域之后,尽管所有iframe具有相同的设置,但在IE 6/7中进入父级时仍然会出错

还有其他一些非常奇怪的东西

在外部/顶级,如果我等待其onload事件,并设置一个计时器,最终我可以到达我需要访问的框架....但我永远无法从下往上... 我真的需要能够

如果我将所有内容设置为foo.com(正如我所说,我不能这样做)它的工作原理! 但出于某种原因,当使用与location.host相同的值时......它不会和它的怪异杀死我......

答案 3 :(得分:2)

我只使用<iframe src="about:blank" ...></iframe>并且效果很好。

答案 4 :(得分:2)

对于IE来说,端口很重要。在域之间,它应该是相同的端口。

答案 5 :(得分:1)

你试过jQuery.contents()吗?

答案 6 :(得分:1)

当您尝试通过document.frames对象访问iframe时,IE似乎出现了问题 - 如果您在变量中存储对创建的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);
}

答案 7 :(得分: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>');

我尝试了几种方法,但这种方法似乎是最好的。您可以在我的博文here中找到一些解释。

答案 8 :(得分:1)

按照Andralor非常简单的方法在这里为我解决了这个问题:https://github.com/fancyapps/fancyBox/issues/766

基本上,再次在o​​nUpdate上调用iframe:

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

答案 9 :(得分:-2)

IE与所有其他浏览器一样使用iframe(至少对于主要功能)。你只需要保留一套规则:

  • 在iframe中加载任何javascript之前(需要了解iframe父级的js部分),确保父级更改了document.domain。
  • 加载所有iframe资源后,将document.domain更改为与parent中定义的相同。 (您需要稍后执行此操作,因为设置域将导致iframe资源的请求失败)

  • 现在你可以为父窗口做一个参考:var winn = window.parent

  • 现在您可以引用父HTML,以便操作它: var parentContent = $(&#39; html&#39;,winn.document)
  • 此时您应该可以访问IE父窗口/文档,您可以随时更改它

答案 10 :(得分:-11)

对我来说,我发现更好的答案是检查访问被拒绝的文件。

我刚刚更新到jQuery-1.8.0.js并在IE9中收到了Access Denied错误。

从Windows资源管理器

  • 我右键单击了选择属性
  • 的文件
  • 选择安全选项卡
  • 点击高级按钮
  • 选择所有者标签
  • 点击编辑按钮
  • 选定的管理员(MachineName \ Administrators)
  • 点击“应用”
  • 关闭所有窗户。

测试了网站。 没有更多问题。

我必须为我刚刚更新的jQuery-UI脚本做同样的事情