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

Posted

技术标签:

【中文标题】尝试访问以编程方式创建的 <iframe> 的文档对象时出现“访问被拒绝”JavaScript 错误(仅限 IE)【英文标题】:"Access is denied" JavaScript error when trying to access the document object of a programmatically-created <iframe> (IE-only) 【发布时间】:2010-12-25 14:03:18 【问题描述】:

我有一个项目,我需要在其中使用 javascript 创建一个

我没有设置

我可以正常工作,但有一个严重的例外 - 如果在父页面中设置了 document.domain 属性(可能是在部署此小部件的某些环境中)、Internet Explorer(可能是所有版本,但我已在 6、7 和 8 中确认)当我尝试访问我创建的此

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

是否有人知道这样做的方法 - 以某种方式设置这个动态创建的

这是我的测试代码:

<!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() 时,我确实有一个

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

【问题讨论】:

troy.onespot 的链接已失效。 【参考方案1】:

你试过jQuery.contents() 吗?

【讨论】:

丹尼斯,好建议,谢谢 - 我试了一下(见 troy.onespot.com/static/access_denied_jquery.html>),但遇到了类似的错误;这次是 jQuery 脚本中的“权限被拒绝”。我怀疑这是相同或类似的障碍。 抱歉,该 URL 已损坏。试试看:troy.onespot.com/static/access_denied_jquery.html 为什么 jQuery 可以神奇地访问 iframe 的文档? @Tim Down:我不认为 jQuery 会拥有神奇的访问权限。相反,jQuery 通常有一些巧妙的技巧来解决跨浏览器问题,并且可能已经实现了解决方法。我同意这不是好兆头,但我认为这是一个很好的建议,值得一试。 这真的不是答案。这只是一个建议,作为对原始帖子的评论可能会更好。【参考方案2】:

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

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

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

在 myiframe.htm 中:

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

【讨论】:

谢谢,大卫 - 我很欣赏这个看似可靠的建议,但除非万不得已,否则我宁愿不采用这种方法。如果我理解正确,模板将需要与父页面位于同一域中(对吗?),这会使我们的客户的实施变得复杂。理想情况下,实现应该像在页面的 HTML 中插入几行 JavaScript 一样简单。 是的,该解决方案确实需要该域上的另一个文件。不过,恐怕这是我能想到的最好的了。 @Bungle:我认为这是你唯一的选择。【参考方案3】:

如果在父页面中设置了 document.domain 属性,Internet Explorer 会给我一个“拒绝访问”

叹息。是的,这是一个 IE 问题(错误?很难说,因为没有针对这种不愉快的记录标准)。当您创建 srcless iframe 时,它​​会从父文档的 location.host 而不是其 document.domain 接收 document.domain。在那一点上,你几乎已经失去了,因为你无法改变它。

一个可怕的解决方法是将src 设置为 javascript: URL (urgh!):

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

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

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

*:出于某些其他原因,您可以在 IE 中,从第二个文档 document.written 由第一个文档设置 document.domain。所以这行得通:

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

此时的丑陋程度对我来说太高了,我出局了。我会像大卫所说的那样做外部 HTML。

【讨论】:

@bobince:你太棒了!经过更多的谷歌搜索后,我确实在昨晚深夜偶然发现了这种方法。事实上,我想我可能已经找到了一个更加健壮,并且可能不那么笨拙的跨浏览器解决方案:telerik.com/community/forums/aspnet-ajax/editor/… - 请注意 Jeff Tucker 从 8 月 21 日发布的帖子。将 这是一个测试页面,说明了我之前的评论:troy.onespot.com/static/access_denied_test.html 哦,太好了!那好多了!有趣的是,直接这样做应该可以工作......通常,一个 javascript: URL 将在其父级的上下文中执行,但 iframe src 似乎并非如此。您也可能会丢失void() 调用,因为该函数已经返回undefined 顺便说一句,当 IE 试图保留 iframe 位置时,在 IE 中重新加载页面时会出错...啊。不知道有没有办法解决这个问题。 @bobince:哦,伙计,你是对的。感谢您指出了这一点;我很兴奋,它第一次工作,我没有费心重新加载。 IE 试图保留 【参考方案4】:

当您尝试通过 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);

【讨论】:

谢谢。这似乎已经解决了我的问题。 奇怪的是,这和我用的一样。工作正常,现在突然间,我一直 getttig access denied 错误【参考方案5】:

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

我刚刚更新到 jQuery-1.8.0.js 并在 IE9 中收到拒绝访问错误。

从 Windows 资源管理器

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

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

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

【讨论】:

我认为您正在解决不同的问题。 OP 正在构建第三方小部件。您不能期望每个访问者都遵循所有这些步骤来显示小部件。【参考方案6】:

其实我有一个非常相似的问题,但有一个转折...... 假设***站点是 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 相同的值时......它并没有,它吓死我......

【讨论】:

【参考方案7】:

我只使用&lt;iframe src="about:blank" ...&gt;&lt;/iframe&gt;,它工作正常。

【讨论】:

【参考方案8】:

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

【讨论】:

【参考方案9】:

我遇到了类似的问题,我的解决方案是这段代码 sn-p(在 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找到一些解释。

【讨论】:

【参考方案10】:

按照 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");
   
 );

【讨论】:

【参考方案11】:

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

在 iframe(需要了解 iframe 父级的 js 部分)中加载任何 javascript 之前,请确保父级已更改 document.domain。

加载所有 iframe 资源后,将 document.domain 更改为与 parent 中定义的相同。 (您需要稍后再执行此操作,因为设置域会导致 iframe 资源的请求失败)

现在您可以对父窗口进行引用:var winn = window.parent

现在您可以引用父 HTML,以便对其进行操作: var parentContent = $('html', winn.document) 此时您应该可以访问 IE 父窗口/文档,并且可以随意更改它

【讨论】:

【参考方案12】:

在父页面中设置document.domain 属性是不够的。 父子节点必须使用相同的 https/http 协议。此外,端口必须相同(如另一个答案中所述)。

因此,例如,如果您导航到

http://subdomain1.yoursite.com/parent.htm

子 iframe 加载自

httpS://subdomain2.yoursite.com/child.htm

然后从孩子到父母的访问将被拒绝。

【讨论】:

以上是关于尝试访问以编程方式创建的 <iframe> 的文档对象时出现“访问被拒绝”JavaScript 错误(仅限 IE)的主要内容,如果未能解决你的问题,请参考以下文章

在 jQuery UI 对话框中以编程方式创建的 iframe 的大小

Android:以编程方式从数组创建微调器

无法通过 *** 以编程方式访问网络路径

JSF2 - 以编程方式创建 HtmloutputLink

使用内置 iOS 日历以编程方式快速创建日历/访问

捕获 iframe 加载完成事件