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

Bun*_*gle 80 javascript iframe internet-explorer dom document

我有一个项目,我需要使用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>
Run Code Online (Sandbox Code Playgroud)

我托管了它:

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

你会看到你是否在IE中加载这个页面,在我调用alert()时,我确实有一个句柄来处理<iframe>的窗口对象; 我只是无法深入到其文档对象中.

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

bob*_*nce 66

如果在父页面中设置了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>'";
Run Code Online (Sandbox Code Playgroud)

但由于某种原因,这样的文档无法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>'";
Run Code Online (Sandbox Code Playgroud)

在这一点上,丑陋程度对我来说太高了,我出局了.我会像大卫那样做外部HTML.

  • @bobince:你太棒了!事实上,经过更多谷歌搜索后,我昨晚做了这个方法.事实上,我想我可能已经找到了一个更强大,可能更少的kludgy跨浏览器解决方案:http://www.telerik.com/community/forums/aspnet-ajax/editor/document-domain-access-denied -in-ie-6.aspx - 请注意Jeff Tucker从8月21日开始的帖子.将<iframe>的"src"属性设置为"javascript:void((function(){document.open(); document.domain =\'tld.com \'; document.close();})())"似乎以跨浏览器的方式完成了这一伎俩.它也适用于Safari(至少v3 +). (10认同)

Dav*_*und 18

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

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

iframe.src = '/myiframe.htm#' + document.domain;
Run Code Online (Sandbox Code Playgroud)

在myiframe.htm中:

document.domain = location.hash.substring(1);
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,大卫 - 我很欣赏看似坚实的建议,但我宁愿不采取这种方法,除非它是最后的手段.如果我理解正确,模板将需要与父页面位于同一个域中(是吗?),这会使我们的客户的实现变得复杂.理想情况下,实现应该像在页面的HTML中插入几行JavaScript一样简单. (3认同)