JavaScript-Fehler "Zugriff verweigert" beim Versuch, auf das Dokumentobjekt eines programmgesteuert erstellten <iframe> (nur IE) zuzugreifen

80

Ich habe ein Projekt, in dem ich ein <iframe> -Element mit JavaScript erstellen und an das DOM anhängen muss. Danach muss ich einige Inhalte in den <iframe> einfügen. Es ist ein Widget, das in Websites von Drittanbietern eingebettet wird.

Ich setze das Attribut "src" des <iframe> nicht, da ich keine Seite laden möchte. Vielmehr wird es verwendet, um den Inhalt, den ich einfüge, zu isolieren / zu boxen, damit ich nicht auf CSS- oder JavaScript-Konflikte mit der übergeordneten Seite stoße. Ich verwende JSONP, um HTML-Inhalte von einem Server zu laden und in diesen <iframe> einzufügen.

Ich habe diese Funktion einwandfrei, mit einer schwerwiegenden Ausnahme - wenn die Eigenschaft document.domain auf der übergeordneten Seite festgelegt ist (was in bestimmten Umgebungen der Fall sein kann, in denen dieses Widget bereitgestellt wird), Internet Explorer (wahrscheinlich alle Versionen, aber ich habe Bestätigt in 6, 7 und 8) gibt mir den Fehler "Zugriff verweigert", wenn ich versuche, auf das Dokumentobjekt dieses von mir erstellten <iframe> zuzugreifen. Es passiert nicht in anderen Browsern, in denen ich getestet habe (alle wichtigen modernen).

Dies ist sinnvoll, da mir bekannt ist, dass Sie in Internet Explorer die document.domain aller Fenster / Frames, die miteinander kommunizieren, auf denselben Wert setzen müssen. Mir ist jedoch keine Möglichkeit bekannt, diesen Wert für ein Dokument festzulegen, auf das ich nicht zugreifen kann.

Ist jemandem eine Möglichkeit bekannt, dies zu tun - irgendwie die document.domain-Eigenschaft dieses dynamisch erstellten <iframe> festlegen? Oder betrachte ich es nicht aus dem richtigen Winkel - gibt es einen anderen Weg, um das zu erreichen, was ich will, ohne auf dieses Problem zu stoßen? Ich muss auf jeden Fall einen <iframe> verwenden, da das isolierte / Sandbox-Fenster für die Funktionalität dieses Widgets von entscheidender Bedeutung ist.

Hier ist mein Testcode:

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

Ich habe es gehostet bei:

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

Wie Sie sehen werden, wenn Sie diese Seite in IE laden, habe ich an dem Punkt, an dem ich alert () aufrufe, ein Handle für das Fensterobjekt des <iframe>. Ich kann einfach nicht tiefer in sein Dokumentobjekt eindringen.

Vielen Dank für jede Hilfe oder Anregungen! Ich bin jedem zu Dank verpflichtet, der mir helfen kann, eine Lösung dafür zu finden.

Patzer
quelle
Der Link für troy.onespot ist tot.
mbomb007

Antworten:

66

Wenn die Eigenschaft document.domain auf der übergeordneten Seite festgelegt ist, gibt mir Internet Explorer die Meldung "Zugriff verweigert".

Seufzer. Ja, es ist ein IE-Problem (Fehler? Schwer zu sagen, da es keinen dokumentierten Standard für diese Art von Unannehmlichkeit gibt). Wenn Sie einen srcless-Iframe erstellen, erhält dieser einen document.domainvom übergeordneten Dokument location.hostanstelle seines document.domain. Zu diesem Zeitpunkt haben Sie so ziemlich verloren, da Sie es nicht ändern können.

Eine schreckliche Problemumgehung besteht darin src, ein Javascript festzulegen: URL (urgh!):

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

Aus irgendeinem Grund kann ein solches Dokument document.domainim IE kein eigenes Skript festlegen (guter alter „nicht angegebener Fehler“), sodass Sie damit keine Brücke zwischen dem übergeordneten Dokument (*) wiederherstellen können. Sie können damit das gesamte Dokument-HTML schreiben, vorausgesetzt, das Widget muss nach der Instanziierung nicht mehr mit dem übergeordneten Dokument kommunizieren.

Allerdings funktionieren iframe-JavaScript-URLs in Safari nicht, sodass Sie immer noch eine Art Browser-Sniffing benötigen, um die zu verwendende Methode auszuwählen.

*: Aus irgendeinem anderen Grunde, Sie können , in IE, gesetzt document.domainvon einem zweiten Dokument, document.written durch das erste Dokument. Das funktioniert also:

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

Zu diesem Zeitpunkt ist die Scheußlichkeit zu hoch für mich, ich bin raus. Ich würde das externe HTML machen, wie David sagte.

Bobince
quelle
10
@ Bobince: Du bist großartig! Ich bin tatsächlich spät in der Nacht auf diesen Ansatz gestoßen, nachdem ich viel mehr gegoogelt hatte. Tatsächlich glaube ich, dass ich eine noch robustere und möglicherweise weniger klobige Cross-Browser-Lösung gefunden habe: telerik.com/community/forums/aspnet-ajax/editor/… - Beachten Sie den Beitrag von Jeff Tucker vom 21. August Das Attribut "src" von iframe> für "javascript: void ((function () {document.open (); document.domain = \ 'tld.com \'; document.close ();}) ())" scheint um den Trick zu machen, und auf eine browserübergreifende Weise. Es funktioniert auch in Safari (mindestens v3 +).
Bungle
1
Hier ist eine Testseite, die meinen vorherigen Kommentar veranschaulicht: troy.onespot.com/static/access_denied_test.html
Bungle
1
Oh toll! Das ist viel besser! Interessant, dass es direkt funktionieren sollte ... normalerweise würde eine Javascript: URL im Kontext des übergeordneten Elements ausgeführt, aber das scheint bei iframe src nicht der Fall zu sein. Sie können den void()Aufruf wahrscheinlich auch verlieren , da die Funktion bereits zurückkehrt undefined.
Bobince
1
Übrigens tritt beim erneuten Laden der Seite im IE ein Fehler auf, da der IE versucht, den iframe-Speicherort beizubehalten ... argh. Keine Ahnung, ob es einen Weg gibt, das zu umgehen.
Bobince
1
@ Bobince: Oh Mann, du hast recht. Vielen Dank für den Hinweis; Ich war so aufgeregt, dass es beim ersten Mal funktionierte, dass ich mich nicht darum kümmerte, neu zu laden. Was meinen Sie damit, dass der IE versucht, den <iframe> -Standort beizubehalten? Ich muss eine Lösung dafür finden, damit ich Sie auf dem Laufenden halte - bitte tun Sie dasselbe, wenn Sie etwas finden.
Bungle
18

Ja, die Zugriffsausnahme ist auf die Tatsache zurückzuführen, dass document.domainsie in Ihrem Elternteil und Ihrem Iframe übereinstimmen muss. Bevor dies der Fall ist, können Sie die document.domainEigenschaft Ihres Iframes nicht programmgesteuert festlegen .

Ich denke, Ihre beste Option hier ist es, die Seite auf eine eigene Vorlage zu verweisen:

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

Und in myiframe.htm:

document.domain = location.hash.substring(1);
David Hedlund
quelle
3
Danke, David - ich schätze einen soliden Vorschlag, aber ich würde diesen Ansatz lieber nicht verfolgen, es sei denn, es ist ein letzter Ausweg. Wenn ich das richtig verstehe, muss die Vorlage auf derselben Domain wie die übergeordnete Seite gespeichert sein (stimmt das?), Und dies würde die Implementierung für unsere Kunden erschweren. Idealerweise sollte die Implementierung so einfach sein wie das Einfügen einiger Zeilen JavaScript in den HTML-Code ihrer Seiten.
Bungle
1
Ja, für die Lösung ist eine weitere Datei in dieser Domäne erforderlich. Ich fürchte, das ist das Beste, was ich mir vorstellen kann.
David Hedlund
1
@Bungle: Ich denke, es ist deine einzige Option.
Tim Down
3

Nun, ich habe tatsächlich ein sehr ähnliches Problem, aber mit einer Wendung ... sagen wir, die Top-Level-Site ist a.foo.com - jetzt setze ich die Dokumentdomäne auf a.foo.com

dann setze ich es in dem iframe, den ich erstelle / besitze, auch auf a.foo.com

Beachten Sie, dass ich sie nicht zu foo.com b / c setzen kann. Es gibt einen anderen Iframe auf der Seite, der auf bafoo.com verweist (der wiederum a.foo.com verwendet, aber ich kann den Skriptcode dort nicht ändern).

Sie werden bemerken, dass ich document.domain im Wesentlichen auf das setze, was es ohnehin schon sein würde ... aber ich muss das tun, um auf den anderen Iframe zuzugreifen, den ich von bafoo.com erwähnt habe

In meinem Frame wird nach dem Festlegen der Domain, obwohl alle Iframes dieselbe Einstellung haben, immer noch eine Fehlermeldung angezeigt, wenn ich in IE 6/7 auf das übergeordnete Element zugegriffen habe

Es gibt andere Dinge, die wirklich bizaree sind

Wenn ich in der Außen- / obersten Ebene auf das Onload-Ereignis warte und einen Timer einstelle, kann ich schließlich in den Frame greifen, auf den ich zugreifen muss ... aber ich kann nie von unten nach oben greifen ... und das wirklich müssen in der Lage sein

auch wenn ich alles auf foo.com setze (was ich, wie gesagt, nicht kann), FUNKTIONIERT ES! aber aus irgendeinem Grund, wenn der gleiche Wert wie location.host verwendet wird ... tut es nicht und es bringt mich um ...

Sean
quelle
2

Ich benutze nur <iframe src="about:blank" ...></iframe>und es funktioniert gut.

jlcooke
quelle
2

Für IE ist der Port wichtig. Zwischen den Domänen sollte es sich um denselben Port handeln.

lwpro2
quelle
1

Haben Sie jQuery.contents () ausprobiert ?

Deniss Kozlovs
quelle
1
Deniss, guter Vorschlag, und danke - ich habe es versucht (siehe < troy.onespot.com/static/access_denied_jquery.html> ), aber einen ähnlichen Fehler erhalten; Dieses Mal ist es "Berechtigung verweigert" im jQuery-Skript. Ich vermute, es ist die gleiche oder eine ähnliche Straßensperre.
Bungle
1
Entschuldigung, diese URL wurde entstellt. Versuchen Sie: troy.onespot.com/static/access_denied_jquery.html
Bungle
4
Warum sollte jQuery magischen Zugriff auf das Iframe-Dokument haben?
Tim Down
8
@ Tim Down: Ich glaube nicht, dass die Annahme war, dass jQuery magischen Zugriff haben würde; Vielmehr hat jQuery häufig einige raffinierte Tricks parat, um browserübergreifende Probleme zu lösen, und möglicherweise bereits eine Problemumgehung implementiert. Ich bin damit einverstanden, dass es nicht gut war, aber ich denke, es war ein guter Vorschlag und einen Versuch wert.
Bungle
Das ist wirklich keine Antwort. Es ist nur ein Vorschlag und wäre wahrscheinlich besser als Kommentar zum ursprünglichen Beitrag.
Neil Monroe
1

Es scheint, dass das Problem mit dem Internet Explorer auftritt, wenn Sie versuchen, über das document.frames-Objekt auf den Iframe zuzugreifen. Wenn Sie einen Verweis auf den erstellten Iframe in einer Variablen speichern, können Sie über die Variable (my_iframe im folgenden Code) auf den injizierten Iframe zugreifen ).

Ich habe dies in IE6 / 7/8 zum Laufen gebracht

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);
}
user299340
quelle
1
Vielen Dank. Dies scheint das Problem für mich behoben zu haben.
Vit
1
Seltsame Sache ist, das war das gleiche, was ich benutzt habe. funktionierte gut, jetzt plötzlich, ich halte getttig Zugriff verweigert Fehler
frostymarvelous
1

Ich hatte ein ähnliches Problem und meine Lösung war dieses Code-Snippet (getestet in IE8 / 9, Chrome und 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>');

Ich habe verschiedene Methoden ausprobiert, aber diese schien die beste zu sein. Einige Erklärungen finden Sie in meinem Blogbeitrag hier .

Zoltan Kochan
quelle
1

Nach der äußerst einfachen Methode von Andralor wurde das Problem für mich behoben: https://github.com/fancyapps/fancyBox/issues/766

Rufen Sie den iframe im Wesentlichen am Update erneut auf:

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

IE funktioniert mit iframe wie alle anderen Browser (zumindest für Hauptfunktionen). Sie müssen nur eine Reihe von Regeln einhalten:

  • Stellen Sie vor dem Laden von Javascript in den Iframe (den Teil von js, der über den Iframe-Elternteil Bescheid wissen muss) sicher, dass der Elternteil die Datei document.domain geändert hat.
  • Wenn alle Iframe-Ressourcen geladen sind, ändern Sie die Datei document.domain so, dass sie mit der im übergeordneten Element definiert ist. (Sie müssen dies später tun, da das Festlegen der Domäne dazu führt, dass die Anforderung der Iframe-Ressource fehlschlägt.)

  • Jetzt können Sie eine Referenz für das übergeordnete Fenster erstellen: var winn = window.parent

  • Jetzt können Sie einen Verweis auf übergeordnetes HTML erstellen, um es zu bearbeiten: var parentContent = $ ('html', winn.document)
  • Zu diesem Zeitpunkt sollten Sie Zugriff auf das übergeordnete IE-Fenster / Dokument haben und können es nach Belieben ändern
Ionut Tocila
quelle
-11

Für mich war die bessere Antwort, die Dateiberechtigungen zu überprüfen, auf die der Zugriff verweigert wird.

Ich habe gerade auf jQuery-1.8.0.js aktualisiert und in IE9 den Fehler "Zugriff verweigert" erhalten.

Aus dem Windows Explorer

  • Ich habe mit der rechten Maustaste auf die Datei geklickt, die Eigenschaften ausgewählt hat
  • Wählen Sie die Registerkarte Sicherheit
  • Klicken Sie auf die Schaltfläche Erweitert
  • Wählen Sie die Registerkarte Eigentümer
  • Klicken Sie auf die Schaltfläche Bearbeiten
  • Ausgewählte Administratoren (Maschinenname \ Administratoren)
  • Klicken Sie auf Übernehmen
  • Alle Fenster geschlossen.

Hat die Seite getestet. Kein Problem mehr.

Ich musste dasselbe für das jQuery-UI-Skript tun, das ich gerade aktualisiert hatte

Mit Kapuze
quelle
2
Ich denke, Sie lösen ein anderes Problem.
Danyal Aytekin
5
Das OP erstellt ein Widget eines Drittanbieters. Sie können nicht erwarten, dass jeder Besucher alle diese Schritte ausführt, um das Widget anzuzeigen.
Christophe