80 votes

Erreur JavaScript "Access is denied" lors de la tentative d'accès à l'objet document d'une <iframe> créée par programme (IE uniquement)

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

Je ne définis pas l'attribut "src" du <iframe> puisque je ne veux pas charger une page ; il est plutôt utilisé pour isoler/envelopper le contenu que j'y insère afin de ne pas rencontrer de conflits CSS ou JavaScript avec la page parent. J'utilise JSONP pour charger du contenu HTML depuis un serveur et l'insérer dans ce <iframe>.

Tout fonctionne bien, à une exception 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, mais j'ai vérifié dans les versions 6, 7 et 8) affiche une erreur "Access is denied" lorsque j'essaie d'accéder à l'objet document du <iframe> que j'ai créé. Cela ne se produit dans aucun des autres navigateurs que j'ai testés (tous les principaux navigateurs modernes).

Cela a un certain sens, puisque je sais qu'Internet Explorer exige que vous définissiez la même valeur pour le document.domain de toutes les fenêtres/cadres qui communiqueront entre elles. Cependant, je ne connais pas de moyen de définir cette valeur sur un document auquel je ne peux pas accéder.

Est-ce que quelqu'un connaît un moyen de le faire - en quelque sorte définir la propriété document.domain de cette <iframe> créée dynamiquement ? Ou est-ce que je ne vois pas les choses sous le bon angle - y a-t-il un autre moyen d'obtenir ce que je cherche sans rencontrer ce problème ? J'ai besoin d'utiliser un <iframe> dans tous les cas, car la fenêtre isolée/sandboxed 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é chez :

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

Comme vous le verrez si vous chargez cette page dans IE, au moment où j'appelle alert(), j'ai une poignée sur l'objet fenêtre de la <iframe> ; je ne peux 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.

66voto

bobince Points 270740

si la propriété document.domain est définie dans la page parent, Internet Explorer me donne un message "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 une iframe srcless, elle reçoit un message de type document.domain du document parent location.host au lieu de son document.domain . À ce stade, vous avez pratiquement perdu, car vous ne pouvez rien y changer.

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

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

Mais pour une raison ou une autre, un tel document est incapable de définir ses propres règles. document.domain de script dans IE (bonne vieille "erreur non spécifiée"), vous ne pouvez donc pas l'utiliser pour rétablir un pont entre le parent(*). Vous pourrait l'utiliser pour écrire l'ensemble du document HTML, en supposant que le widget n'a pas besoin de parler à son document parent une fois qu'il est instancié.

Toutefois, les URL JavaScript des iframes ne fonctionnent pas dans Safari. Il vous faudra donc utiliser une méthode de reniflage du navigateur pour choisir la méthode à utiliser.

* : Pour une autre raison, vous peut dans l'IE, définir document.domain d'un second 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>'";

A ce stade, le niveau de hideur est trop élevé pour moi, je m'en vais. Je ferais le HTML externe comme David l'a dit.

18voto

David Hedlund Points 66192

Eh bien oui, l'exception d'accès est due au fait que document.domain doivent correspondre dans votre parent et dans votre iframe, et avant qu'ils ne le fassent, vous ne pourrez pas définir par programmation l'élément document.domain de votre iframe.

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

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

Et dans myiframe.htm :

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

3voto

Sean Points 11

En fait, j'ai un problème très similaire, mais avec une particularité... disons que le site de premier niveau est a.foo.com - maintenant j'ai fixé le domaine du document à a.foo.com

puis dans la iframe que j'ai créée, je l'ai aussi définie comme a.foo.com.

notez que je ne peux pas les mettre sur foo.com parce qu'il y a un autre iframe dans la page qui pointe sur b.a.foo.com (qui utilise a.foo.com mais je ne peux pas changer le code script là)

vous remarquerez que je mets essentiellement 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é depuis b.a.foo.com

à l'intérieur de mon cadre, après avoir défini le domaine, bien que toutes les iframes aient le même paramètre, j'obtiens toujours une erreur lorsque j'atteins le parent dans IE 6/7.

Il y a d'autres choses qui sont vraiment bizarres.

dans le niveau extérieur / supérieur, si j'attends son événement onload, et que je règle une minuterie, je peux éventuellement descendre dans le cadre auquel je dois accéder....mais je ne peux jamais descendre de bas en haut... et j'ai vraiment besoin d'être capable de

De plus, si je configure tout pour être foo.com (ce que, comme je l'ai dit, je ne peux pas faire), cela fonctionne ! mais pour une raison quelconque, lorsque j'utilise la même valeur que location.host.... cela ne fonctionne pas et cela me tue.....

1voto

Deniss Kozlovs Points 2519

Avez-vous essayé jQuery.contents() ?

1voto

user299340 Points 9

Il semble que le problème avec IE survient 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 réussi à le faire fonctionner 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);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X