Detectar el error si iframe src no se carga. Error: - "Se negó a mostrar 'http://www.google.co.in/' en un marco ..."

79

Estoy usando Knockout.jspara vincular la srcetiqueta iframe (esto será configurable con respecto al usuario).

Ahora, si el usuario ha configurado http://www.google.com (sé que no se cargará en iframe, por eso lo estoy usando para un escenario -ve) y eso debe mostrarse en IFrame. pero arroja error: -

Se negó a mostrar " http://www.google.co.in/ " en un marco porque estableció "X-Frame-Options" en "SAMEORIGIN".

Tengo el siguiente código para Iframe: -

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

Lo que quiero es, si la URL no se carga. Quiero mostrar un mensaje personalizado . Captura de pantalla de la consola cuando obtengo un error FIDDLE AQUÍ

Ahora, si uso onload y onerror como: -

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

Funciona bien cargando w3schools.com pero no con google.com.

En segundo lugar: si lo hago como una función y lo intento como lo hice en mi violín, no funciona.

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

No sé cómo debería ejecutarlo y capturar el error.

Editado: - He visto que desea llamar a una función si el iframe no se carga o carga la pregunta en stackoverflow, pero muestra un error para los sitios que se pueden cargar en iframe.

Además, he examinado el iframe de Stackoverflow en el evento de carga ¡Gracias!

Shubh
fuente

Respuestas:

44

No podrá hacer esto desde el lado del cliente debido a la Política del mismo origen establecida por los navegadores. No podrá obtener mucha información del iFrame aparte de las propiedades básicas como su ancho y alto.

Además, google establece en su encabezado de respuesta un ' X-Frame-Options ' de SAMEORIGIN.

Incluso si hizo una llamada ajax a Google, no podrá inspeccionar la respuesta porque el navegador aplica la Política del mismo origen.

Entonces, la única opción es realizar la solicitud desde su servidor para ver si puede mostrar el sitio en su IFrame.

Entonces, en su servidor ... su aplicación web haría una solicitud a www.google.com y luego inspeccionaría la respuesta para ver si tiene un argumento de encabezado de X-Frame-Options. Si existe, entonces sabrá que el IFrame producirá un error.

Evan Larsen
fuente
Roblox utiliza un iframetruco para detectar si el juego está instalado mediante la <iframe src="roblox-player:foo">detección de un controlador de URI personalizado. Al detectar este iframeerror, aparece el botón "Descargar". ¿Cómo lo hacen entonces?
2017
1
@QZ Support No tengo idea de qué estás hablando.
Evan Larsen
1
@EvanLarsen Estoy mencionando un videojuego muy popular que usa con éxito la <iframe>técnica para iniciar (y esperaba detectar) un controlador URI registrado en el sistema operativo. Es un juego gratuito, puedes instalarlo y comprobarlo por ti mismo. Cuando te unes a un juego a través del navegador, utiliza un truco de iframe para iniciar el juego. Si falla, muestran el botón "descargar". De alguna manera saben si el URI se manejó correctamente o no. Mi suposición inicial fue detectar el iframeerror, pero las respuestas (así como mis pruebas) parecen sugerir que no es posible. ¿Cómo saben cuando falla el iframe?
3 de
Esto es solo una suposición, pero apuesto a que el sitio web solo está llamando a una aplicación web alojada en su máquina local. Si la llamada falla, muestra el botón de descarga. Una vez que descargue e instale el juego en su máquina, el sitio web podrá llamar a la aplicación web local autohospedada. Por aplicación web autohospedada ... me refiero simplemente a una aplicación con puntos finales http a la que puede llamar cualquier sitio web que la conozca. (es decir, localhost: 7845 / opengame / room / 2534 )
Evan Larsen
La localhost:7845es bastante suposición. Primero, alcanzará advertencias / errores de contenido mixto (roblox.com usa HTTPS) y luego, necesitaría puertos de conmutación por error en caso de conflictos. La técnica utilizada para iniciar el software es iframe. Esto se puede observar examinando la fuente de la página. De alguna manera, cuando esto no inicia el software, pueden detectarlo. Esto se puede hacer a través de un método de "teléfono a casa" + tiempo de espera usando el ID del rastreador del navegador. Menciono esto porque esta iframedetección de fallas es útil para iniciar aplicaciones asociadas, pero solo si se puede detectar la falla.
tresf
15

Creo que puede vincular el loadevento del iframe, el evento se activa cuando el contenido del iframe está completamente cargado.

Al mismo tiempo, puede iniciar un setTimeout, si el iFrame está cargado, borre el tiempo de espera o deje que se active el tiempo de espera.

Código:

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

});

Demostración: http://jsfiddle.net/IrvinDominin/QXc6P/

Segundo problema

Es porque pierde los parens en la llamada de función en línea; intenta cambiar esto:

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

dentro de esto:

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

Demostración: http://jsfiddle.net/IrvinDominin/ALBXR/4/

Irvin Dominin
fuente
51
Oye, solo mira el violín, nunca arroja un error.
vvohra87
12
Estoy en Ubuntu y Chrome; no importa qué URL ponga en el cuadro de texto, dice "hecho" y "hecho func" :(
vvohra87
3
@IrvinDomininakaEdward: el enlace de ambos violines no funciona ... no se abre ... ¿ha eliminado el violín?
Hitesh
10
menos 1 porque como dicen los comentarios anteriores: el violín nunca arroja el mensaje de error esperado cuando el iframe no se carga. esto se debe a que el evento de carga de iframe se activa incluso cuando no carga el contenido.
CodeToad
3
Esta no debería ser la respuesta seleccionada. El de Evan a continuación es correcto: la seguridad del navegador evita que se detecte.
Scott Smith
9

La carga siempre será un disparador, soluciono este problema, use el bloque try catch. Lanzará una excepción cuando intente obtener el contentDocument.

iframe.onload = function(){
   var that = $(this)[0];
   try{
        that.contentDocument;
   }
   catch(err){
        //TODO 
   }
}
H. Edén
fuente
1
¡Esta es la forma más sencilla que he encontrado hasta ahora y en realidad también funciona!
Simon Jackson
15
Esto tampoco funciona para dominios cruzados; arrojará un error de cualquier manera
Luoruize
Esto funcionó para mí, para el iframe de mi propio dominio. X-Frame-Options: SAMEORIGIN
Ryan
para mí arroja la misma excepción incluso cuando el iframe cargó el contenido. ¿cómo saber si el contenido no está cargado?
leeCoder
¡Estaba a punto de responder que es posible detectar ese error de esta manera! ¡Pero ya lo hiciste! Estoy manejando exactamente el mismo problema (y también para verificar si el usuario fue redirigido a una determinada página en mi dominio) de esta manera. Me encontré con esta pregunta buscando "manejo de errores en iframe", ¡pero ahora estoy enfrentando un error 503 dentro de un iframe!
Sampgun
8

Esta es una ligera modificación a la respuesta de Edens, que para mí en Chrome no detectó el error. Aunque seguirá recibiendo un error en la consola: "Se negó a mostrar ' https://www.google.ca/ ' en un marco porque configuró 'X-Frame-Options' en 'sameorigin'". Al menos esto captará el mensaje de error y luego podrá solucionarlo.

 <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>
usuario2677034
fuente
Esto da como resultado el error "no se puede leer la 'ubicación' de la propiedad nula" that.contentDocumenty muchos sitios de trabajo seguirán arrojando un error that.contentWindowdurante el proceso de carga.
Carrito abandonado el
1

Me enfrenté a un problema similar. Lo resolví sin usar el controlador de carga. Estaba trabajando en el proyecto AngularJs, así que usé $ interval y $ timeout. U también puede usar setTimeout y setInterval. Aquí está el código:

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

Cada 0.4 segundos sigue revisando el encabezado del documento iFrame. Algo está presente CORS no detuvo la carga ya que el error CORS muestra una página en blanco. Si no hay nada presente después de 5 segundos, hubo algún error (política de Cors), etc. Mostrar mensaje adecuado. Gracias. Espero que resuelva tu problema.

viresh
fuente
2
Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "..." from accessing a cross-origin frame.- ¿Está seguro de que funciona entre dominios?
Mars Robertson
0

Tengo el mismo problema, Chrome no puede disparar un error cuando el iframe src carga el error.

pero en mi caso, solo necesito hacer una solicitud http de dominio cruzado, así que uso el script src / onload / onerror en lugar de iframe. está funcionando bien.

Engin Morse
fuente
0

Lo resolví con window.length. Pero con esta solución puede tomar el error actual (X-Frame o 404).

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

MSDN

Qeemerc
fuente
0

Como se explica en la respuesta aceptada, https://stackoverflow.com/a/18665488/4038790 , debe verificar a través de un servidor.

Debido a que no hay una forma confiable de verificar esto en el navegador, le sugiero que cree un punto final de servidor rápido que pueda usar para verificar si alguna URL se puede cargar a través de iframe. Una vez que su servidor esté en funcionamiento, simplemente envíele una solicitud AJAX para verificar cualquier URL proporcionando la URL en la cadena de consulta como url(o lo que desee su servidor). Aquí está el código del servidor en 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
fuente