Catch-Fehler, wenn iframe src nicht geladen werden kann. Fehler: - "Weigert sich," http://www.google.co.in/ "in einem Frame anzuzeigen."

79

Ich verwende Knockout.js, um das Iframe- srcTag zu binden (dies kann in Bezug auf den Benutzer konfiguriert werden).

Wenn der Benutzer http://www.google.com konfiguriert hat (ich weiß, dass es nicht in iframe geladen wird, verwende ich es deshalb für das Szenario -ve) und dies in IFrame angezeigt werden muss. aber es wirft Fehler: -

Es wurde abgelehnt, " http://www.google.co.in/ " in einem Frame anzuzeigen, da "X-Frame-Optionen" auf "SAMEORIGIN" gesetzt wurde.

Ich habe den folgenden Code für Iframe: -

<iframe class="iframe" id="iframe" data-bind="attr: {src: externalAppUrl, height: iframeheight}">
    <p>Hi, This website does not supports IFrame</p>
</iframe>

Was ich will ist, wenn die URL nicht geladen werden kann. Ich möchte eine benutzerdefinierte Nachricht anzeigen . Screenshot der Konsole, wenn ich eine Fehlermeldung erhalte FIDDLE HIER

Nun, wenn ich onload und onerror verwende als: -

<iframe id="browse" style="width:100%;height:100%" onload="alert('Done')" onerror="alert('Failed')"></iframe>

Es funktioniert gut, w3schools.com zu laden, aber nicht mit google.com.

Zweitens: - Wenn ich es als Funktion mache und versuche, wie ich es in meiner Geige getan habe, funktioniert es nicht.

<iframe id="browse" style="width:100%;height:100%" onload="load" onerror="error"></iframe>

Ich weiß nicht, wie ich es ausführen und den Fehler erfassen soll.

Bearbeitet: - Ich habe gesehen , dass Sie eine Funktion aufrufen möchten, wenn iframe nicht geladen wird oder die Frage im Stackoverflow geladen wird, aber ein Fehler für Sites angezeigt wird, die in iframe geladen werden können.

Außerdem habe ich mir Stackoverflow iframe on load event angesehen. Danke !!

Shubh
quelle

Antworten:

44

Sie können dies auf der Clientseite aufgrund der von den Browsern festgelegten Richtlinie für denselben Ursprung nicht tun . Sie können vom iFrame nur grundlegende Eigenschaften wie Breite und Höhe erhalten.

Außerdem setzt Google in seinem Antwortheader die ' X-Frame-Optionen ' von SAMEORIGIN.

Selbst wenn Sie einen Ajax-Anruf bei Google getätigt haben, können Sie die Antwort nicht überprüfen, da der Browser die Richtlinie für denselben Ursprung erzwingt.

Die einzige Möglichkeit besteht darin, eine Anfrage von Ihrem Server zu stellen, um festzustellen, ob Sie die Site in Ihrem IFrame anzeigen können.

Auf Ihrem Server stellt Ihre Web-App eine Anfrage an www.google.com und überprüft dann die Antwort, um festzustellen, ob sie ein Header-Argument für X-Frame-Optionen enthält. Wenn es existiert, wissen Sie, dass der IFrame einen Fehler macht.

Evan Larsen
quelle
Roblox verwendet einen iframeTrick, um zu erkennen, ob das Spiel installiert ist, <iframe src="roblox-player:foo">indem ein benutzerdefinierter URI-Handler erkannt wird . Wenn Sie diesen iframeFehler erkennen, wird die Schaltfläche "Herunterladen" angezeigt. Wie machen sie das dann?
Tresf
1
@ QZ Support Ich habe keine Ahnung, wovon du sprichst.
Evan Larsen
1
@EvanLarsen Ich erwähne ein sehr beliebtes Videospiel, das diese <iframe>Technik erfolgreich einsetzt, um einen im Betriebssystem registrierten URI-Handler zu starten (und ich hatte gehofft, ihn zu erkennen). Es ist ein kostenloses Spiel, Sie können es installieren und selbst sehen. Wenn Sie einem Spiel über den Browser beitreten, wird das Spiel mithilfe eines Iframe-Hacks gestartet. Wenn dies fehlschlägt, wird die Schaltfläche "Herunterladen" angezeigt. Irgendwie wissen sie, ob die URI richtig gehandhabt wurde oder nicht. Meine anfängliche Vermutung war, den iframeFehler zu erkennen, aber die Antworten (sowie meine Tests) scheinen darauf hinzudeuten, dass dies nicht möglich ist. Woher wissen sie, wann der Iframe ausfällt?
Tresf
Dies ist nur eine Vermutung, aber ich wette, die Website ruft nur eine selbst gehostete Web-App auf Ihrem lokalen Computer auf. Wenn der Anruf fehlschlägt, wird die Schaltfläche zum Herunterladen angezeigt. Sobald Sie das Spiel heruntergeladen und auf Ihrem Computer installiert haben, kann die Website die lokale selbst gehostete Web-App aufrufen. Mit selbst gehosteter Web-App meine ich nur eine App mit http-Endpunkten, die von jeder Website aufgerufen werden kann, die davon weiß. (dh localhost: 7845 / opengame / room / 2534 )
Evan Larsen
Das localhost:7845ist durchaus die Annahme. Erstens werden Warnungen / Fehler in Bezug auf gemischte Inhalte angezeigt (roblox.com verwendet HTTPS), und als Nächstes werden bei Konflikten Failover-Ports benötigt. Die Technik zum Starten der Software ist eine iframe. Dies kann durch Untersuchen der Seitenquelle beobachtet werden. Wenn die Software dadurch nicht gestartet werden kann, können sie sie irgendwie erkennen. Dies kann über eine "Telefon-Home" + Timeout-Methode unter Verwendung der Browser-Tracker-ID erfolgen. Ich erwähne dies, weil diese iframeFehlererkennung zum Starten zugehöriger Apps nützlich ist, aber nur, wenn der Fehler erkannt werden kann.
Tresf
15

Ich denke, dass Sie das loadEreignis des Iframes binden können, das Ereignis wird ausgelöst, wenn der Iframe-Inhalt vollständig geladen ist.

Gleichzeitig können Sie ein setTimeout starten. Wenn der iFrame geladen ist, löschen Sie das Timeout. Lassen Sie das Timeout alternativ ausgelöst.

Code:

var iframeError;

function change() {
    var url = $("#addr").val();
    $("#browse").attr("src", url);
    iframeError = setTimeout(error, 5000);
}

function load(e) {
    alert(e);
}

function error() {
    alert('error');
}

$(document).ready(function () {
    $('#browse').on('load', (function () {
        load('ok');
        clearTimeout(iframeError);
    }));

});

Demo: http://jsfiddle.net/IrvinDominin/QXc6P/

Zweites Problem

Dies liegt daran, dass Sie die Parens im Inline-Funktionsaufruf verpassen. Versuchen Sie dies zu ändern:

<iframe id="browse" style="width:100%;height:100%" onload="load" onerror="error"></iframe>

das sehr gut finden:

<iframe id="browse" style="width:100%;height:100%" onload="load('Done func');" onerror="error('failed function');"></iframe>

Demo: http://jsfiddle.net/IrvinDominin/ALBXR/4/

Irvin Dominin
quelle
51
Hey, habe nur die Geige angeschaut - sie wirft nie einen Fehler.
vvohra87
12
Ich bin auf Ubuntu und Chrome - egal welche URL ich in das Textfeld eingegeben habe, es heißt "erledigt" und "erledigt func" :(
vvohra87
3
@IrvinDomininakaEdward: Beide Geigen-Links funktionieren nicht ... sie öffnen sich nicht ... haben Sie die Geige gelöscht?
Hitesh
10
minus 1, da in den obigen Kommentaren angegeben ist: Die Geige gibt niemals die erwartete Fehlermeldung aus, wenn der Iframe nicht geladen werden kann. Dies liegt daran, dass das Ladeereignis von iframe auch dann ausgelöst wird, wenn der Inhalt nicht geladen wird.
CodeToad
3
Dies sollte nicht die ausgewählte Antwort sein. Die folgende von Evan ist korrekt: Die Browsersicherheit verhindert, dass dies erkannt wird.
Scott Smith
8

Das Onload wird immer ausgelöst, ich habe dieses Problem mit try catch block behoben. Es wird eine Ausnahme auslösen, wenn Sie versuchen, das contentDocument abzurufen.

iframe.onload = function(){
   var that = $(this)[0];
   try{
        that.contentDocument;
   }
   catch(err){
        //TODO 
   }
}
H.Eden
quelle
1
Dies ist der einfachste Weg, den ich bisher gefunden habe, und er funktioniert auch!
Simon Jackson
15
Dies funktioniert auch nicht für
domänenübergreifende
Dies funktionierte für mich, für den Iframe meiner eigenen Domain. X-Frame-Optionen: SAMEORIGIN
Ryan
Für mich löst es die gleiche Ausnahme aus, selbst wenn der Iframe den Inhalt geladen hat. Woher wissen Sie, ob der Inhalt nicht geladen ist?
LeeCoder
Ich wollte gerade antworten, dass es möglich ist, diesen Fehler auf diese Weise zu erkennen! Aber du hast es schon getan! Ich behandle genau das gleiche Problem (und überprüfe auch, ob der Benutzer auf eine bestimmte Seite in meiner Domain umgeleitet wurde) auf diese Weise! Ich bin auf diese Frage gestoßen, als ich nach "Fehler im Iframe behandeln" gesucht habe, aber jetzt sehe ich einen 503-Fehler in einem Iframe!
Sampgun
8

Dies ist eine geringfügige Änderung der Antwort von Edens - die für mich in Chrom den Fehler nicht erkannt hat. Obwohl in der Konsole immer noch eine Fehlermeldung angezeigt wird: "Die Anzeige von" https://www.google.ca/ "in einem Frame wurde abgelehnt, da" X-Frame-Optionen "auf" sameorigin "gesetzt wurde." Zumindest wird dadurch die Fehlermeldung abgefangen und Sie können damit umgehen.

 <iframe id="myframe" src="https://google.ca"></iframe>

 <script>
 myframe.onload = function(){
 var that = document.getElementById('myframe');

 try{
    (that.contentWindow||that.contentDocument).location.href;
 }
 catch(err){
    //err:SecurityError: Blocked a frame with origin "http://*********" from accessing a cross-origin frame.
    console.log('err:'+err);
}
}
</script>
user2677034
quelle
Dies führt zu dem Fehler "Die Eigenschaft 'Position' von Null kann nicht gelesen werden" für that.contentDocumentund viele Arbeitswebsites werfen that.contentWindowwährend des Ladevorgangs immer noch einen Fehler auf .
Verlassener Wagen
1

Ich hatte ein ähnliches Problem. Ich habe es ohne Verwendung des Onload-Handlers gelöst. Ich habe an AngularJs Projekt gearbeitet, also habe ich $ interval und $ timeout verwendet. Sie können auch setTimeout und setInterval verwenden. Hier ist der Code:

 var stopPolling;
 var doIframePolling;
 $scope.showIframe = true;
 doIframePolling = $interval(function () {
    if(document.getElementById('UrlIframe') && document.getElementById('UrlIframe').contentDocument.head && document.getElementById('UrlIframe').contentDocument.head.innerHTML != ''){
        $interval.cancel(doIframePolling);
        doIframePolling = undefined;
        $timeout.cancel(stopPolling);
        stopPolling = undefined;
        $scope.showIframe = true;
    }
},400);

stopPolling = $timeout(function () {
        $interval.cancel(doIframePolling);
        doIframePolling = undefined;
        $timeout.cancel(stopPolling);
        stopPolling = undefined;
        $scope.showIframe = false;     
},5000);

 $scope.$on("$destroy",function() {
        $timeout.cancel(stopPolling);
        $interval.cancel(doIframePolling);
 });

Überprüfen Sie alle 0,4 Sekunden den Kopf des iFrame-Dokuments. Ich habe etwas vorhanden. Das Laden wurde von CORS nicht gestoppt, da der CORS-Fehler eine leere Seite anzeigt. Wenn nach 5 Sekunden nichts mehr vorhanden ist, ist ein Fehler aufgetreten (Cors-Richtlinie) usw. Geeignete Meldung anzeigen. Danke. Ich hoffe es löst dein Problem.

viresh
quelle
2
Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "..." from accessing a cross-origin frame.- Sind Sie sicher, dass es domänenübergreifend funktioniert?
Mars Robertson
0

Ich habe das gleiche Problem, Chrome kann keinen Fehler auslösen, wenn iframe src Ladefehler.

In meinem Fall muss ich nur eine domänenübergreifende http-Anfrage stellen, daher verwende ich das Skript src / onload / onerror anstelle von iframe. es funktioniert gut.

Engin Morse
quelle
0

Ich habe es mit gelöst window.length. Mit dieser Lösung können Sie jedoch einen aktuellen Fehler (X-Frame oder 404) erkennen.

iframe.onload = event => {
   const isLoaded = event.target.contentWindow.window.length // 0 or 1
}

MSDN

Qeemerc
quelle
0

Wie in der akzeptierten Antwort https://stackoverflow.com/a/18665488/4038790 erläutert , müssen Sie dies über einen Server überprüfen.

Da es keine zuverlässige Möglichkeit gibt, dies im Browser zu überprüfen, sollten Sie sich einen schnellen Serverendpunkt erstellen, mit dem Sie überprüfen können, ob eine URL über iframe geladen werden kann. Sobald Ihr Server betriebsbereit ist, senden Sie einfach eine AJAX-Anfrage an ihn, um eine URL zu überprüfen, indem Sie die URL in der Abfragezeichenfolge als url(oder was auch immer Ihr Server wünscht) angeben. Hier ist der Servercode in NodeJs:

const express = require('express')
const app = express()

app.get('/checkCanLoadIframeUrl', (req, res) => {
  const request = require('request')
  const Q = require('q')

  return Q.Promise((resolve) => {
    const url = decodeURIComponent(req.query.url)

    const deafultTimeout = setTimeout(() => {
      // Default to false if no response after 10 seconds
      resolve(false)
    }, 10000)

    request({
        url,
        jar: true /** Maintain cookies through redirects */
      })
      .on('response', (remoteRes) => {
        const opts = (remoteRes.headers['x-frame-options'] || '').toLowerCase()
        resolve(!opts || (opts !== 'deny' && opts !== 'sameorigin'))
        clearTimeout(deafultTimeout)
      })
      .on('error', function() {
        resolve(false)
        clearTimeout(deafultTimeout)
      })
  }).then((result) => {
    return res.status(200).json(!!result)
  })
})

app.listen(process.env.PORT || 3100)

lwdthe1
quelle