当尝试访问程序创建的 < iframe > (IE-only)的文档对象时,出现 JavaScript 错误

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

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

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

这是有道理的,因为我知道,Internet Explorer 需要你设置所有 windows/frame 的 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 > 窗口对象的句柄; 我只是不能深入到它的文档对象中。

非常感谢您的帮助和建议!谁能帮我找到解决办法,我就感激不尽。

206359 次浏览

你试过 JQuery. content ()吗?

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

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

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

在 myiframe. htm 中:

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

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

唉。是的,这是一个 IE 问题(错误?很难说,因为这种不愉快没有文件标准)。当您创建一个 srless iframe 时,它从父文档的 location.host而不是它的 document.domain接收一个 document.domain。在这一点上,你几乎已经失去了,因为你不能改变它。

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

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

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

然而 iframe JavaScript URL 在 Safari 中不能工作,所以您仍然需要某种浏览器嗅探来选择使用哪种方法。

* : 由于某些其他原因,您在 IE 中从第一个文档编写的第二个文档 document 中设置 document.domain。所以,这个方法是有效的:

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

在这一点上,可怕的水平太高,我出来了。我会像 David 说的那样做外部 HTML。

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

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

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

文件资源管理器

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

测试现场。 没问题了。

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

其实我也有一个类似的问题,但是..。 假设顶级站点是 a.foo.com-现在我将 document domain 设置为 a.foo.com

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

请注意,我不能设置它们 too foo.com b/c 页面中有另一个指向 b.a.foo.com 的 iframe (它同样使用 a.foo.com,但我不能更改那里的脚本代码)

您会注意到,我实际上将 document.domain 设置为它本来应该是的样子... ... 但是我必须这样做才能访问我在 b.a.foo.com 上提到的另一个 iframe

在我的框架内部,在我设置了域之后,即使所有的 iframe 都有相同的设置,当我到达 IE6/7的父目录时仍然会得到一个错误

还有一些事情真的很奇怪

在外部/顶层,如果我等待它的 onload 事件,并设置一个定时器,最终我可以达到我需要访问的帧... 但我永远不能达到自下而上..。 我真的需要能够

还有,如果我把所有东西都设置为 foo.com (我说过我不能这么做) ,它就能工作! 但是由于某种原因,当使用与 location.host 相同的值时... ... 它没有,而且它真是要了我的命... ..。

我只是使用 <iframe src="about:blank" ...></iframe>,它工作得很好。

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

我也遇到过类似的问题,我的解决方案就是这个代码片段(在 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>');

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

用来自 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");
}
});

IE 和其他浏览器一样使用 iframe (至少对于主函数是这样)。你只需要遵守一套规则:

  • 在加载 iframe 中的任何 javascript (js 中需要了解 iframe 父节点的那部分)之前,确保父节点已经更改了 document.domain。
  • 加载所有 iframe 资源时,将 document.domain 更改为与父节点中定义的相同。(稍后需要这样做,因为设置域将导致 iframe 资源的请求失败)

  • 现在您可以为父窗口创建一个引用: var winn = window.father

  • 现在您可以引用父 HTML,以便对其进行操作: Var ParentContent = $(‘ html’,winn.document)
  • 在这一点上,你应该有访问 IE 父窗口/文档,你可以改变它,因为你想要的

在父页中设置 document.domain属性是不够的。父代和子代都必须使用相同的 https/http 协议.另外,端口必须是相同的(正如这里在另一个答案中提到的)。

例如,如果导航到

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

子 iframe 从

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

那么从子女到父母的访问将被拒绝。