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


80

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

我不想设置<iframe>的“ src”属性,因为我不想加载页面。相反,它用于隔离/沙盒我插入其中的内容,以免与父页面发生CSS或JavaScript冲突。我正在使用JSONP从服务器加载一些HTML内容并将其插入此<iframe>中。

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

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

有谁知道执行此操作的方法-以某种方式设置此动态创建的<iframe>的document.domain属性吗?还是我不是从正确的角度看待它-是否有另一种方法可以实现我想要的目标而又不会遇到这个问题?无论如何,我确实需要使用<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>的window对象上有一个句柄。我只是无法更深入地了解其文档对象。

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


troy.onespot的链接已死。
mbomb007 '18

Answers:


66

如果在父页面中设置了document.domain属性,则Internet Explorer会提示我“访问被拒绝”

叹。是的,这是IE问题(错误?很难说,因为没有记录下来的关于这种不愉快的标准)。创建无src的iframe时,它会收到document.domain来自父文档的,location.host而不是的document.domain。那时,由于无法更改,您已经迷失了很多。

可怕的解决方法是将srcjavascript设置为URL :(网址!):

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

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

但是,iframe JavaScript URL在Safari中不起作用,因此您仍然需要某种浏览器嗅探才能选择要使用的方法。

*:由于其他原因,您可以在IE中document.domain从第二个文档(由第一个文档编写)中设置。所以这有效:

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

在这一点上,我的恐惧程度太高了,我已经出局了。我会像David所说的那样做外部HTML。


10
@bobince:你太棒了!在经过更多Google搜寻之后,我确实在昨晚深夜发现了这种方法。实际上,我想我可能已经找到了一个更强大,更可能不太灵活的跨浏览器解决方案:telerik.com/community/forums/aspnet-ajax/editor / ...-请注意Jeff Tucker在8月21日发布的帖子。 iframe>的“ src”属性似乎是“ javascript:void((function(){document.open(); document.domain = \'tld.com \'; document.close();})())”并以跨浏览器的方式来完成操作。它也可以在Safari(至少v3 +)中使用。
Bungle,

1
这是一个测试页面,阐明了我之前的评论:troy.onespot.com/static/access_denied_test.html
Bungle,2009年

1
太棒了!那好多了!有趣的是,直接执行此操作应该可以正常工作...通常,一个javascript:URL将在其父级上下文中执行,但iframe src似乎并非如此。void()由于该函数已经返回,您也可能会丢失呼叫undefined
bobince

1
顺便说一句,由于IE尝试保留iframe位置,因此在IE中重新加载页面时会出错。邓诺(Dunno)如果可以解决的话。
bobince

1
@bobince:哦,老兄,你是对的。感谢您指出了这一点; 我感到非常兴奋,以至于它第一次起作用就让我不用费心重新加载。IE试图保留<iframe>位置是什么意思?我必须为此找到解决方案,所以我会及时通知您-如果您碰巧发现任何问题,也请这样做。
Bungle 2009年

18

好吧,是的,访问例外是由于document.domain必须在父项和iframe中匹配,因此在访问它们之前,您将无法以编程方式设置document.domainiframe的属性。

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

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

在myiframe.htm中:

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

3
谢谢,大卫-感谢您提出的可靠建议,但我宁愿不采取这种方法,除非万不得已。如果我理解正确,则模板将需要与父页面位于同一域中(是吗?),这会使我们的客户的实现复杂化。理想情况下,实现应该像在页面的HTML中插入几行JavaScript一样简单。
Bungle,

1
是的,该解决方案确实需要该域上的另一个文件。不过,恐怕这是我能想到的最好的方法。
大卫Hedlund的

1
@Bungle:我认为这是您唯一的选择。
Tim Down

3

好吧,我实际上有一个非常相似的问题,但有一点曲折...说顶级站点是a.foo.com-现在我将文档域设置为a.foo.com

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

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

您会注意到,即时通讯本质上是将document.domain设置为已经存在的内容...但是我必须这样做才能访问我从bafoo.com提及的其他iframe

在我的框架内,设置完域后,即使所有iframe都具有相同的设置,但在IE 6/7中到达父级时仍然会出错

还有其他一些事情,实际上是bizaree

在外面/顶层,如果我等待它的onload事件并设置一个计时器,最终我可以进入需要访问的帧...但是我永远无法从下往上到达...而且我真的需要能够

如果我将所有内容都设置为foo.com(正如我说的那样,我做不到),那么它也可以工作!但是由于某种原因,当使用与location.host相同的值时....它并没有和它的怪癖杀死我.....


2

我只是用<iframe src="about:blank" ...></iframe>它,它工作正常。


2

对于IE,端口很重要。在域之间,它应该是同一端口。


1

您是否尝试过jQuery.contents()


1
丹尼斯(Deniss),很好的建议,谢谢你-我了一下(请参阅< troy.onespot.com/static/access_denied_jquery.html>),但是出现了类似的错误;这次是jQuery脚本中的“权限被拒绝”。我怀疑这是相同或相似的障碍。
Bungle,

1
抱歉,该网址已损坏。试试:troy.onespot.com/static/access_denied_jquery.html
Bungle,

4
jQuery为什么会神奇地访问iframe文档?
Tim Down

8
@Tim Down:我不认为jQuery具有神奇的访问权限。相反,jQuery经常有一些巧妙的技巧可以解决跨浏览器的问题,并且可能已经实现了解决方法。我同意这不是一个好兆头,但我认为这是一个很好的建议,值得一试。
Bungle 2009年

这真的不是答案。这只是一个建议,作为对原始帖子的评论可能会更好。
尼尔·梦露

1

当您尝试通过document.frames对象访问iframe时,似乎出现了IE的问题-如果您将对创建的iframe的引用存储在变量中,则可以通过变量(下面的代码中的my_iframe访问访问的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
谢谢。这似乎为我解决了问题。
vit

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>');

我尝试了几种方法,但这似乎是最好的。你可以在我的博客文章一些解释这里



-2

IE与所有其他浏览器一样都可以与iframe一起使用(至少在主要功能方面)。您只需要保留一组规则:

  • 在iframe(需要了解iframe父级的js部分)中加载任何javascript之前,请确保父级的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资源管理器

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

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

我也必须对刚刚更新的jQuery-UI脚本执行相同的操作


2
我认为您正在解决另一个问题。
Danyal Aytekin

5
OP正在构建第三方窗口小部件。您不能期望每个访客都遵循所有这些步骤来显示小部件。
Christophe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.