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

时间:2021-10-01 15:56:08

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创建一个

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>.

我没有设置

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(可能是所有版本,但我已经当我尝试访问我创建的

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.

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

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 &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>

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()时,我确实有一个句柄来处理

Thanks very much for any help or suggestions! I'll be indebted to whomever can help me find a solution to this.

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

11 个解决方案

#1


64  

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.domain from the parent document's location.host instead of its document.domain. At that point you've pretty much lost as you can't change it.

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

A horrendous workaround is to set src to a javascript: URL (urgh!):

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

 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.domain from script in IE (good old “unspecified error”), so you can't use that to regain a bridge between the parent(*). You could use it to write the whole document HTML, assuming the widget doesn't need to talk to its parent document once it's instantiated.

但由于某种原因,这样的文档无法从IE中的脚本设置自己的document.domain(旧的“未指定的错误”),因此您不能使用它来重新获得父(*)之间的桥梁。您可以使用它来编写整个文档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.domain from a second document, document.written by the first document. So this works:

*:由于某些其他原因,您可以在IE中从第二个文档设置document.domain,document.writing由第一个文档编写。这样可行:

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。

#2


18  

Well yes, the access exception is due to the fact that document.domain must match in your parent and your iframe, and before they do, you won't be able to programmatically set the document.domain property of your iframe.

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

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);

#3


3  

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指向b.a.foo.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设置为它已经存在的东西......但我必须这样做以访问我从b.a.foo.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相同的值....它不会和它的怪物杀了我.....

#4


2  

I just use <iframe src="about:blank" ...></iframe> and it works fine.

我只是使用

#5


2  

for IE, the port matters. In between domains, it should be same port.

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

#6


1  

Have you tried jQuery.contents() ?

你试过jQuery.contents()吗?

#7


1  

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的引用,那么您可以通过变量访问注入的iframe(下面的代码中的my_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);
}

#8


1  

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.

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

#9


1  

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:

基本上,再次在o​​nUpdate上调用iframe:

$('a.js-fancybox-iframe').fancybox({
    type: 'iframe',
    scrolling : 'visible',
    autoHeight: true,
    onUpdate: function(){
     $("iframe.fancybox-iframe");
   }
 });

#10


-2  

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.
  • 在iframe中加载任何javascript(需要了解iframe父级的js部分)之前,请确保父级更改了document.domain。
  • 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)

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

  • now you can make a reference for parent window: var winn = window.parent

    现在你可以为父窗口做一个引用:var winn = window.parent

  • now you can make a reference to parent HTML, in order to manipulate it: var parentContent = $('html', winn.document)
  • 现在你可以引用父HTML,以便操作它: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
  • 此时您应该可以访问IE父窗口/文档,您可以随意更改它

#11


-10  

For me I found the better answer was to check the file permissons that access is being denied to.

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

I just update to jQuery-1.8.0.js and was getting the Access Denied error in IE9.

我只是更新到jQuery-1.8.0.js并在IE9中获得了Access Denied错误。

From Windows Explorer

从Windows资源管理器

  • I right clicked on the file selected the Properties
  • 我右键单击了选中属性的文件
  • Selected the Security Tab
  • 选择安全选项卡
  • Clicked the Advanced Button
  • 单击“高级”按钮
  • Selected the Owner Tab
  • 选择所有者选项卡
  • Clicked on Edit Button
  • 单击“编辑”按钮
  • Selected Administrators(MachineName\Administrators)
  • 选定的管理员(MachineName \ Administrators)
  • Clicked Apply
  • 单击“应用”
  • Closed all the windows.
  • 关闭所有窗户。

Tested the site. No more issue.

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

I had to do the same for the the jQuery-UI script I had just updated as well

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

#1


64  

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.domain from the parent document's location.host instead of its document.domain. At that point you've pretty much lost as you can't change it.

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

A horrendous workaround is to set src to a javascript: URL (urgh!):

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

 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.domain from script in IE (good old “unspecified error”), so you can't use that to regain a bridge between the parent(*). You could use it to write the whole document HTML, assuming the widget doesn't need to talk to its parent document once it's instantiated.

但由于某种原因,这样的文档无法从IE中的脚本设置自己的document.domain(旧的“未指定的错误”),因此您不能使用它来重新获得父(*)之间的桥梁。您可以使用它来编写整个文档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.domain from a second document, document.written by the first document. So this works:

*:由于某些其他原因,您可以在IE中从第二个文档设置document.domain,document.writing由第一个文档编写。这样可行:

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。

#2


18  

Well yes, the access exception is due to the fact that document.domain must match in your parent and your iframe, and before they do, you won't be able to programmatically set the document.domain property of your iframe.

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

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);

#3


3  

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指向b.a.foo.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设置为它已经存在的东西......但我必须这样做以访问我从b.a.foo.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相同的值....它不会和它的怪物杀了我.....

#4


2  

I just use <iframe src="about:blank" ...></iframe> and it works fine.

我只是使用

#5


2  

for IE, the port matters. In between domains, it should be same port.

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

#6


1  

Have you tried jQuery.contents() ?

你试过jQuery.contents()吗?

#7


1  

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的引用,那么您可以通过变量访问注入的iframe(下面的代码中的my_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);
}

#8


1  

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.

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

#9


1  

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:

基本上,再次在o​​nUpdate上调用iframe:

$('a.js-fancybox-iframe').fancybox({
    type: 'iframe',
    scrolling : 'visible',
    autoHeight: true,
    onUpdate: function(){
     $("iframe.fancybox-iframe");
   }
 });

#10


-2  

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.
  • 在iframe中加载任何javascript(需要了解iframe父级的js部分)之前,请确保父级更改了document.domain。
  • 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)

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

  • now you can make a reference for parent window: var winn = window.parent

    现在你可以为父窗口做一个引用:var winn = window.parent

  • now you can make a reference to parent HTML, in order to manipulate it: var parentContent = $('html', winn.document)
  • 现在你可以引用父HTML,以便操作它: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
  • 此时您应该可以访问IE父窗口/文档,您可以随意更改它

#11


-10  

For me I found the better answer was to check the file permissons that access is being denied to.

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

I just update to jQuery-1.8.0.js and was getting the Access Denied error in IE9.

我只是更新到jQuery-1.8.0.js并在IE9中获得了Access Denied错误。

From Windows Explorer

从Windows资源管理器

  • I right clicked on the file selected the Properties
  • 我右键单击了选中属性的文件
  • Selected the Security Tab
  • 选择安全选项卡
  • Clicked the Advanced Button
  • 单击“高级”按钮
  • Selected the Owner Tab
  • 选择所有者选项卡
  • Clicked on Edit Button
  • 单击“编辑”按钮
  • Selected Administrators(MachineName\Administrators)
  • 选定的管理员(MachineName \ Administrators)
  • Clicked Apply
  • 单击“应用”
  • Closed all the windows.
  • 关闭所有窗户。

Tested the site. No more issue.

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

I had to do the same for the the jQuery-UI script I had just updated as well

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