web-dev-qa-db-fra.com

Erreur JavaScript "Accès refusé" lors de la tentative d'accès à l'objet de document d'un <iframe> créé par programme (IE uniquement)

J'ai un projet dans lequel j'ai besoin de créer un élément <iframe> en utilisant JavaScript et de l'ajouter au DOM. Après cela, je dois insérer du contenu dans <iframe>. C'est un widget qui sera intégré à des sites Web tiers.

Je ne définit pas l'attribut "src" de <iframe> car je ne souhaite pas charger de page; au lieu de cela, il est utilisé pour isoler/sandbox le contenu que j'y insère afin que je ne rencontre pas de conflits CSS ou JavaScript avec la page parente. J'utilise JSONP pour charger du contenu HTML à partir d'un serveur et l'insérer dans cette <iframe>.

Je fonctionne très bien, à une exception grave près: si la propriété document.domain est définie dans la page parent (ce qui peut être le cas dans certains environnements dans lesquels ce widget est déployé), Internet Explorer (probablement toutes les versions). confirmé en 6, 7 et 8) me donne une erreur "Accès refusé" lorsque je tente d'accéder à l'objet de document de cet <iframe> que j'ai créé. Cela ne se produit pas dans les autres navigateurs dans lesquels j'ai testé (tous les principaux actuels).

Cela a du sens, car je suis conscient qu'Internet Explorer nécessite que vous définissiez le document.domaine de toutes les fenêtres/images qui communiqueront entre elles avec la même valeur. Cependant, je ne connais aucun moyen de définir cette valeur sur un document auquel je ne peux pas accéder.

Est-ce que quelqu'un est au courant d'un moyen de faire cela - en quelque sorte définir la propriété document.domain de ce <iframe> créé dynamiquement? Ou est-ce que je ne le regarde pas du bon angle - y a-t-il un autre moyen de réaliser ce que je cherche sans me heurter à ce problème? Dans tous les cas, j'ai besoin d'utiliser un <iframe>, car la fenêtre isolée/en bac à sable est cruciale pour la fonctionnalité de ce widget.

Voici mon code de test:

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

Je l'ai hébergé à:

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

Comme vous le constaterez si vous chargez cette page dans IE, au moment où j'appelle alert (), j'ai un descripteur sur l'objet window du <iframe>; Je ne peux tout simplement pas aller plus loin dans son objet document.

Merci beaucoup pour toute aide ou suggestion! Je serai redevable à quiconque pourra m'aider à trouver une solution à ce problème.

79
Bungle

si la propriété document.domain est définie dans la page parent, Internet Explorer me donne un "Accès refusé"

Soupir. Oui, c'est un problème IE (bug? Difficile à dire car il n'y a pas de norme documentée pour ce genre de désagrément)). Lorsque vous créez un iframe sans srcless, il reçoit un document.domain le document parent location.Host au lieu de document.domain. À ce stade, vous avez quasiment perdu car vous ne pouvez pas le modifier.

Une solution de contournement horrible consiste à définir src en javascript: URL (urgh!):

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

Mais pour une raison quelconque, un tel document est incapable de définir son propre document.domain À partir d'un script dans IE (bon vieux “erreur non spécifiée”)), vous ne pouvez donc pas l'utiliser pour retrouver un pont entre le parent (*). Vous pourriez l'utiliser pour écrire l'intégralité du document HTML, en supposant que le widget n'a pas besoin de parler à son document parent une fois qu'il est instancié.

Cependant, les URL JavaScript iframe ne fonctionnent pas dans Safari, vous devez donc toujours utiliser une sorte de recherche de navigateur pour choisir la méthode à utiliser.

*: Pour une autre raison, vous can, dans IE, définissez document.domain À partir d'un deuxième document, document.écrit par le premier document. Donc ça marche:

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

À ce stade, le niveau de hidosité est trop élevé pour moi, je suis absent. Je ferais le HTML externe comme David l'a dit.

66
bobince

Eh bien oui, l'exception d'accès est due au fait que document.domain doit correspondre dans votre parent et votre iframe, et avant cela, vous ne pourrez pas définir par programme le document.domain propriété de votre iframe.

Je pense que votre meilleure option ici est de pointer la page sur un modèle de votre choix:

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

Et dans myiframe.htm:

document.domain = location.hash.substring(1);
18
David Hedlund

eh bien, j’ai en fait un problème très similaire, mais avec une torsion ... disons que le site de niveau supérieur est a.foo.com - maintenant j’ai défini le domaine de document sur a.foo.com

puis dans l'iframe que je crée/possède, je le mets aussi a.foo.com

notez que je ne peux pas les définir trop foo.com b/c il y a un autre iframe dans la page pointée vers b.a.foo.com (qui utilise à nouveau a.foo.com mais je ne peux pas changer le code du script ici)

vous remarquerez que je suis essentiellement en train de fixer document.domain à ce qu'il serait déjà de toute façon ... mais je dois le faire pour accéder à l'autre iframe que j'ai mentionné de b.a.foo.com

dans mon cadre, après avoir défini le domaine, même si tous les iframes ont le même paramètre, j'obtiens toujours une erreur en atteignant le parent dans IE 6/7

il y a d'autres choses qui r vraiment bizaree

à l'extérieur/niveau supérieur, si j'attends son événement onload et que je règle une minuterie, je peux éventuellement atteindre le cadre dont j'ai besoin pour accéder à ... mais je ne peux jamais atteindre de bas en haut ... et vraiment besoin de pouvoir

aussi si je mets tout pour être foo.com (ce qui, comme je l'ai dit, je ne peux pas le faire), ça marche! mais pour une raison quelconque, lorsque vous utilisez la même valeur que location.Host ... il ne le fait pas et sa panique me tue ...

3
Sean

pour IE, le port compte. Entre les domaines, il devrait s'agir du même port.

2
lwpro2

Je viens d'utiliser <iframe src="about:blank" ...></iframe> et ça marche bien.

2
jlcooke

J'ai eu un problème similaire et ma solution était cet extrait de code (testé dans IE8/9, Chrome et 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>');

J'ai essayé plusieurs méthodes mais celle-ci semblait être la meilleure. Vous pouvez trouver quelques explications dans mon article de blog ici .

1
Zoltan Kochan

Avez-vous essayé jQuery.contents () ?

1
Deniss Kozlovs

Il semble que le problème avec IE survienne lorsque vous essayez d'accéder à l'iframe via l'objet document.frames - si vous stockez une référence à l'iframe créé dans une variable, vous pouvez accéder à l'iframe injecté. via la variable (my_iframe dans le code ci-dessous).

J'ai obtenu cela pour travailler dans 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);
}
1
user299340

En suivant la méthode extrêmement simple d'Andralor, le problème a été résolu pour moi: https://github.com/fancyapps/fancyBox/issues/766

Essentiellement, appelez à nouveau l'iframe onUpdate:

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