尝试访问以编程方式创建的 <iframe> 的文档对象时出现“访问被拒绝”JavaScript 错误(仅限 IE)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1886547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Access is denied" JavaScript error when trying to access the document object of a programmatically-created <iframe> (IE-only)
提问by Bungle
I have project in which I need to create an <iframe> element using JavaScript and append it to the DOM. After that, I need to insert some content into the <iframe>. It's a widget that will be embedded in third-party websites.
我有一个项目,我需要在其中使用 JavaScript 创建一个 <iframe> 元素并将其附加到 DOM。之后,我需要在 <iframe> 中插入一些内容。这是一个将嵌入第三方网站的小部件。
I don't set the "src" attribute of the <iframe> since I don't want to load a page; rather, it is used to isolate/sandbox the content that I insert into it so that I don't run into CSS or JavaScript conflicts with the parent page. I'm using JSONP to load some HTML content from a server and insert it in this <iframe>.
我没有设置 <iframe> 的“src”属性,因为我不想加载页面;相反,它用于隔离/沙箱我插入的内容,这样我就不会遇到与父页面的 CSS 或 JavaScript 冲突。我正在使用 JSONP 从服务器加载一些 HTML 内容并将其插入到这个 <iframe> 中。
I have this working fine, with one serious exception - if the document.domain property is set in the parent page (which it may be in certain environments in which this widget is deployed), Internet Explorer (probably all versions, but I've confirmed in 6, 7, and 8) gives me an "Access is denied" error when I try to access the document object of this <iframe> I've created. It doesn't happen in any other browsers I've tested in (all major modern ones).
我有这个工作正常,有一个严重的例外 - 如果 document.domain 属性设置在父页面(它可能在部署此小部件的某些环境中),Internet Explorer(可能是所有版本,但我已经在 6、7 和 8 中确认)当我尝试访问我创建的这个 <iframe> 的文档对象时,出现“访问被拒绝”错误。在我测试过的任何其他浏览器(所有主要的现代浏览器)中都不会发生这种情况。
This makes some sense, since I'm aware that Internet Explorer requires you to set the document.domain of all windows/frames that will communicate with each other to the same value. However, I'm not aware of any way to set this value on a document that I can't access.
这是有道理的,因为我知道 Internet Explorer 要求您将所有将相互通信的窗口/框架的 document.domain 设置为相同的值。但是,我不知道有什么方法可以在我无法访问的文档上设置此值。
Is anyone aware of a way to do this - somehow set the document.domain property of this dynamically created <iframe>? Or am I not looking at it from the right angle - is there another way to achieve what I'm going for without running into this problem? I do need to use an <iframe> in any case, as the isolated/sandboxed window is crucial to the functionality of this widget.
有没有人知道这样做的方法 - 以某种方式设置这个动态创建的 <iframe> 的 document.domain 属性?或者我不是从正确的角度看它 - 有没有另一种方法可以在不遇到这个问题的情况下实现我的目标?我确实需要在任何情况下使用 <iframe>,因为隔离/沙盒窗口对于此小部件的功能至关重要。
Here's my test code:
这是我的测试代码:
<!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>
I've hosted it at:
我已将其托管在:
http://troy.onespot.com/static/access_denied.html
http://troy.onespot.com/static/access_denied.html
As you'll see if you load this page in IE, at the point that I call alert(), I do have a handle on the window object of the <iframe>; I just can't get any deeper, into its document object.
如果您在 IE 中加载此页面,您将看到,在我调用 alert() 时,我确实在 <iframe> 的 window 对象上有一个句柄;我无法更深入地了解它的文档对象。
Thanks very much for any help or suggestions! I'll be indebted to whomever can help me find a solution to this.
非常感谢您的任何帮助或建议!我将感谢任何能帮助我找到解决方案的人。
采纳答案by bobince
if the document.domain property is set in the parent page, Internet Explorer gives me an "Access is denied"
如果在父页面中设置了 document.domain 属性,Internet Explorer 会给我一个“访问被拒绝”
Sigh. Yeah, it's an IE issue (bug? difficult to say as there is no documented standard for this kind of unpleasantness). When you create a srcless iframe it receives a document.domainfrom the parent document's location.hostinstead of its document.domain. At that point you've pretty much lost as you can't change it.
叹。是的,这是一个 IE 问题(错误?很难说,因为没有针对这种不愉快的记录标准)。当您创建一个 srcless iframe 时,它会document.domain从父文档的location.host而不是它的document.domain. 那时你已经失去了很多,因为你无法改变它。
A horrendous workaround is to set srcto a javascript: URL (urgh!):
一个可怕的解决方法是设置src为 javascript: URL(呃!):
iframe.src= "javascript:'<html><body><p>Hello<\/p><script>do things;<\/script>'";
But for some reason, such a document is unable to set its own document.domainfrom script in IE (good old “unspecified error”), so you can't use that to regain a bridge between the parent(*). You coulduse it to write the whole document HTML, assuming the widget doesn't need to talk to its parent document once it's instantiated.
但是出于某种原因,这样的文档无法document.domain在 IE 中设置自己的脚本(好老的“未指定错误”),因此您不能使用它来重新建立父级 (*) 之间的桥梁。您可以使用它来编写整个文档 HTML,假设小部件在实例化后不需要与其父文档对话。
However iframe JavaScript URLs don't work in Safari, so you'd still need some kind of browser-sniffing to choose which method to use.
但是 iframe JavaScript URL 在 Safari 中不起作用,因此您仍然需要某种浏览器嗅探来选择要使用的方法。
*: For some other reason, you can, in IE, set document.domainfrom a second document, document.written by the first document. So this works:
*:由于某些其他原因,您可以在 IE 中document.domain从第二个文档进行设置,即由第一个文档编写的文档。所以这有效:
if (isIE)
iframe.src= "javascript:'<script>window.onload=function(){document.write(\'<script>document.domain=\\""+document.domain+"\\";<\\/script>\');document.close();};<\/script>'";
At this point the hideousness level is too high for me, I'm out. I'd do the external HTML like David said.
在这一点上,丑陋程度对我来说太高了,我出去了。我会像大卫说的那样做外部 HTML。
回答by dxh
Well yes, the access exception is due to the fact that document.domainmust match in your parent and your iframe, and before they do, you won't be able to programmatically set the document.domainproperty of your iframe.
是的,访问异常是由于document.domain必须在您的父级和 iframe 中匹配,在它们匹配之前,您将无法以编程方式设置document.domainiframe的属性。
I think your best option here is to point the page to a template of your own:
我认为您最好的选择是将页面指向您自己的模板:
iframe.src = '/myiframe.htm#' + document.domain;
And in myiframe.htm:
在 myiframe.htm 中:
document.domain = location.hash.substring(1);
回答by Sean
well i actually have a very similar problem, but with a twist... say the top level site is a.foo.com - now i set document domain to a.foo.com
好吧,我实际上有一个非常相似的问题,但有一个转折...说顶级站点是 a.foo.com - 现在我将文档域设置为 a.foo.com
then in the iframe that i create / own,i also set it too a.foo.com
然后在我创建/拥有的 iframe 中,我也将它设置为 a.foo.com
note that i cant set them too foo.com b/c there is another iframe in the page pointed to b.a.foo.com (which again uses a.foo.com but i cant change the script code there)
请注意,我也不能设置它们 foo.com b/c 页面中有另一个 iframe 指向 bafoo.com(它再次使用 a.foo.com,但我无法更改那里的脚本代码)
youll note that im essentially setting document.domain to what it already would be anyway...but i have to do that to access the other iframe i mentioned from b.a.foo.com
你会注意到我基本上将 document.domain 设置为它已经是什么......但我必须这样做才能访问我从 bafoo.com 提到的另一个 iframe
inside my frame, after i set the domain, eventhough all iframes have the same setting, i still get an error when reaching up into the parent in IE 6/7
在我的框架内,在我设置域后,即使所有 iframe 都具有相同的设置,在 IE 6/7 中到达父级时仍然出现错误
there are other things that r really bizaree
还有其他事情真的很奇怪
in the outside / top level, if i wait for its onload event, and set a timer, eventually i can reach down into the frame i need to access....but i can never reach from bottom up... and i really need to be able to
在外部/顶层,如果我等待它的 onload 事件,并设置一个计时器,最终我可以深入到我需要访问的框架中......但我永远无法从下往上......而且我真的需要能够
also if i set everything to be foo.com (which as i said i cannot do) IT WORKS! but for some reason, when using the same value as location.host....it doesnt and its freaking killing me.....
此外,如果我将所有内容都设置为 foo.com(正如我所说,我不能这样做)它可以工作!但出于某种原因,当使用与 location.host 相同的值时......
回答by jlcooke
I just use <iframe src="about:blank" ...></iframe>and it works fine.
我只是使用<iframe src="about:blank" ...></iframe>,它工作正常。
回答by lwpro2
for IE, the port matters. In between domains, it should be same port.
对于 IE,端口很重要。在域之间,它应该是相同的端口。
回答by Zoltan Kochan
I had a similar issue and my solution was this code snippet (tested in IE8/9, Chrome and Firefox)
我有一个类似的问题,我的解决方案是这个代码片段(在 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>');
I've tried several methods but this one appeared to be the best. You can find some explanations in my blog post here.
我尝试了几种方法,但这种方法似乎是最好的。你可以在我的博客文章一些解释这里。
回答by Tim Denison
Following the exceedingly simple method from Andralor here fixed the issue for me: https://github.com/fancyapps/fancyBox/issues/766
按照 Andralor 的极其简单的方法在这里为我解决了这个问题:https: //github.com/fancyapps/fancyBox/issues/766
Essentially, call the iframe again onUpdate:
本质上,在更新时再次调用 iframe:
$('a.js-fancybox-iframe').fancybox({
type: 'iframe',
scrolling : 'visible',
autoHeight: true,
onUpdate: function(){
$("iframe.fancybox-iframe");
}
});
回答by user299340
It seems that the problem with IE comes when you try and access the iframe via the document.frames object - if you store a reference to the created iframe in a variable then you can access the injected iframe via the variable (my_iframe in the code below).
当您尝试通过 document.frames 对象访问 iframe 时,似乎 IE 的问题出现了 - 如果您将创建的 iframe 的引用存储在变量中,那么您可以通过变量(下面代码中的 my_iframe)访问注入的 iframe )。
I've gotten this to work in IE6/7/8
我已经让它在 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);
}
回答by Deniss Kozlovs
Have you tried jQuery.contents()?
你试过jQuery.contents()吗?
回答by Ionut Tocila
IE works with iframe like all the other browsers (at least for main functions). You just have to keep a set of rules:
IE 像所有其他浏览器一样使用 iframe(至少对于主要功能)。你只需要遵守一套规则:
- before you load any javascript in the iframe (that part of js which needs to know about the iframe parent), ensure that the parent has document.domain changed.
when all iframe resources are loaded, change document.domain to be the same as the one defined in parent. (You need to do this later because setting domain will cause the iframe resource's request to fail)
now you can make a reference for parent window: var winn = window.parent
- now you can make a reference to parent HTML, in order to manipulate it: var parentContent = $('html', winn.document)
- at this point you should have access to IE parent window/document and you can change it as you wont
- 在 iframe 中加载任何 javascript(需要了解 iframe 父级的 js 部分)之前,请确保父级已更改 document.domain。
加载所有 iframe 资源后,将 document.domain 更改为与 parent 中定义的相同。(后面需要做这个,因为设置domain会导致iframe资源的请求失败)
现在你可以为父窗口做一个参考:var winn = window.parent
- 现在您可以引用父 HTML,以便对其进行操作: var parentContent = $('html', winn.document)
- 此时您应该可以访问 IE 父窗口/文档,您可以随意更改它

