尝试访问以编程方式创建的 <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 <iframe>.</p>
<div id="placeholder"></div>
<p>This is a paragraph below the <iframe>.</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 日发布的帖子。将void()
调用,因为该函数已经返回undefined
。
顺便说一句,当 IE 试图保留 iframe 位置时,在 IE 中重新加载页面时会出错...啊。不知道有没有办法解决这个问题。
@bobince:哦,伙计,你是对的。感谢您指出了这一点;我很兴奋,它第一次工作,我没有费心重新加载。 IE 试图保留 当您尝试通过 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】:我只使用<iframe src="about:blank" ...></iframe>
,它工作正常。
【讨论】:
【参考方案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)的主要内容,如果未能解决你的问题,请参考以下文章