Ошибка перехвата, если iframe src не загружается. Ошибка: - «Не удалось отобразить" http://www.google.co.in/ "во фрейме ..»

79

Я использую Knockout.jsдля привязки srcтега iframe (это можно настроить в соответствии с пользователем).

Теперь, если пользователь настроил http://www.google.com (я знаю, что он не будет загружаться в iframe, поэтому я использую его для сценария -ve), и это должно быть показано в IFrame. но это вызывает ошибку: -

Отказался отображать " http://www.google.co.in/ " во фрейме, потому что для параметра "X-Frame-Options" установлено значение "SAMEORIGIN".

У меня есть следующий код для Iframe: -

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

Я хочу, чтобы URL-адрес не загружался. Я хочу отображать настраиваемое сообщение . Скриншот консоли при появлении ошибки FIDDLE ЗДЕСЬ

Теперь, если я использую onload и onerror как: -

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

Он отлично работает при загрузке w3schools.com, но не с google.com.

Во-вторых: - если я сделаю это как функцию и попробую, как я сделал на своей скрипке, это не сработает.

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

Я не знаю, как мне запустить его и зафиксировать ошибку.

Отредактировано: - Я видел, что хочу вызвать функцию, если iframe не загружает или не загружает вопрос в stackoverflow, но показывает ошибку для сайтов, которые могут быть загружены в iframe.

Кроме того, я просмотрел Stackoverflow iframe при загрузке события Спасибо !!

Шубх
источник

Ответы:

44

Вы не сможете сделать это на стороне клиента из-за той же политики происхождения, установленной браузерами. Вы не сможете получить из iFrame много информации, кроме основных свойств, таких как ширина и высота.

Кроме того, Google устанавливает в своем заголовке ответа « X-Frame-Options » SAMEORIGIN.

Даже если вы выполнили ajax-вызов в Google, вы не сможете проверить ответ, потому что браузер применяет ту же политику происхождения.

Итак, единственный вариант - сделать запрос с вашего сервера, чтобы узнать, можете ли вы отобразить сайт в своем IFrame.

Итак, на вашем сервере ... ваше веб-приложение отправит запрос на www.google.com, а затем проверит ответ, чтобы увидеть, есть ли у него аргумент заголовка X-Frame-Options. Если он существует, вы знаете, что IFrame выдаст ошибку.

Эван Ларсен
источник
Roblox использует iframeуловку, чтобы определить, установлена ​​ли игра, <iframe src="roblox-player:foo">путем обнаружения пользовательского обработчика URI. При обнаружении этого iframeсбоя появляется кнопка «Загрузить». Как они тогда это делают?
tresf
1
@QZ Support Я не понимаю, о чем вы говорите.
Эван Ларсен
1
@EvanLarsen Я упоминаю очень популярную видеоигру, которая успешно использует эту <iframe>технику для запуска (и я надеялся обнаружить) обработчика URI, зарегистрированного в ОС. Это бесплатная игра, вы можете установить ее и убедиться в этом сами. Когда вы присоединяетесь к игре через браузер, он использует взлом iframe для запуска игры. Если не получается, показывают кнопку "скачать". Каким-то образом они знают, правильно ли обработан URI. Моя первоначальная догадка заключалась в обнаружении iframeошибки, но ответы (а также мои тесты), похоже, предполагают, что это невозможно. Как они узнают, что iframe не работает?
tresf
Это всего лишь предположение, но я уверен, что веб-сайт просто вызывает автономное веб-приложение на вашем локальном компьютере. Если вызов не удался, то отображается кнопка загрузки. После того, как вы загрузите и установите игру на свой компьютер, веб-сайт сможет вызывать локальное собственное веб-приложение. Под собственным веб-приложением ... Я имею в виду просто приложение с конечными точками http, которое может быть вызвано любым веб-сайтом, который знает об этом. (т.е. localhost: 7845 / opengame / room / 2534 )
Эван Ларсен
Это localhost:7845вполне предположение. Во-первых, он выдает предупреждения / ошибки смешанного содержимого (roblox.com использует HTTPS), а затем ему потребуются порты аварийного переключения в случае конфликтов. Для запуска программного обеспечения используется метод iframe. Это можно увидеть, изучив исходный код страницы. Каким-то образом, когда это не запускает программное обеспечение, они могут его обнаружить. Это может быть сделано с помощью метода "домашний телефон" + тайм-аут с использованием идентификатора отслеживания браузера. Я упоминаю об этом, потому что это iframeобнаружение сбоя полезно для запуска связанных приложений, но только в том случае, если сбой можно обнаружить.
tresf
15

Я думаю, что вы можете привязать loadсобытие iframe, событие срабатывает, когда содержимое iframe полностью загружено.

В то же время вы можете запустить setTimeout, если iFrame загружен, сбросьте тайм-аут или позвольте тайм-ауту сработать.

Код:

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

});

Демо: http://jsfiddle.net/IrvinDominin/QXc6P/

Вторая проблема

Это потому, что вы пропустили скобки в вызове встроенной функции; попробуйте изменить это:

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

в это:

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

Демо: http://jsfiddle.net/IrvinDominin/ALBXR/4/

Ирвин Доминин
источник
51
Эй, только что посмотрел на скрипку - никогда не выдает ошибок.
vvohra87 02
12
Я использую Ubuntu и Chrome - независимо от того, какой URL я
ввожу
3
@IrvinDomininakaEdward: ссылка на обе скрипки не работает ... она не открывается ... вы удалили скрипку?
Hitesh
10
минус 1, потому что, как указано в комментариях выше: скрипка никогда не выдает ожидаемое сообщение об ошибке, когда iframe не загружается. это потому, что событие загрузки iframe срабатывает, даже если он не загружает контент.
CodeToad,
3
Это не должен быть выбранный ответ. Приведенная ниже фраза Эвана верна: безопасность браузера не позволяет это обнаружить.
Скотт Смит
9

Загрузка всегда будет триггером, я люблю эту проблему, используя блок try catch. Он вызовет исключение, когда вы попытаетесь получить contentDocument.

iframe.onload = function(){
   var that = $(this)[0];
   try{
        that.contentDocument;
   }
   catch(err){
        //TODO 
   }
}
Х. Иден
источник
1
Это самый простой способ, с которым я когда-либо сталкивался, и он действительно работает!
Саймон Джексон
15
Это также не работает для перекрестных доменов - в любом случае это
вызовет
Это сработало для меня, для iframe моего собственного домена. X-Frame-Options: SAMEORIGIN
Ryan
для меня это вызывает то же исключение, даже когда iframe загружает контент. как узнать, не загружен ли контент?
leeCoder
Я собирался ответить, что таким образом можно отловить эту ошибку! Но вы уже это сделали! Я обрабатываю ту же самую проблему (а также проверяю, был ли пользователь перенаправлен на определенную страницу в моем домене) таким образом! Я столкнулся с этим вопросом в поиске «обработки ошибок в iframe», но теперь я столкнулся с ошибкой 503 внутри iframe!
Sampgun
8

Это небольшая модификация ответа Edens, которая для меня в chrome не обнаружила ошибку. Хотя вы по-прежнему будете получать ошибку в консоли: «Отказался отображать ' https://www.google.ca/ ' во фрейме, потому что для 'X-Frame-Options' установлено значение 'sameorigin'». По крайней мере, это поймает сообщение об ошибке, и тогда вы сможете с ней справиться.

 <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
источник
Это приводит к ошибке «не удается прочитать свойство 'location' of null», that.contentDocumentи многие рабочие сайты по-прежнему будут выдавать ошибку that.contentWindowво время процесса загрузки.
Брошенная тележка
1

Я столкнулся с подобной проблемой. Я решил это без использования обработчика onload. Я работал над проектом AngularJs, поэтому использовал $ interval и $ timeout. U также может использовать setTimeout и setInterval. Вот код:

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

Каждые 0,4 секунды проверяйте заголовок документа iFrame. Я что-то присутствует. CORS не остановил загрузку, так как ошибка CORS показывает пустую страницу. Если через 5 секунд ничего не отображается, произошла ошибка (политика Cors) и т. Д. Покажите подходящее сообщение. Спасибо. Надеюсь, это решит вашу проблему.

Виреш
источник
2
Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "..." from accessing a cross-origin frame.- вы уверены, что он работает междоменно?
Марс Робертсон,
0

У меня такая же проблема, хром не может запустить ошибку при ошибке загрузки iframe src.

но в моем случае мне просто нужно сделать междоменный http-запрос, поэтому я использую скрипт src / onload / onerror вместо iframe. это работает хорошо.

Энгин Морс
источник
0

Я решил это с помощью window.length. Но с этим решением вы можете взять текущую ошибку (X-Frame или 404).

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

MSDN

Qeemerc
источник
0

Как объяснено в принятом ответе https://stackoverflow.com/a/18665488/4038790 , вам необходимо проверить через сервер.

Поскольку нет надежного способа проверить это в браузере, я предлагаю вам создать себе быструю конечную точку сервера, которую вы можете использовать, чтобы проверить, загружается ли какой-либо URL-адрес через iframe. После того, как ваш сервер будет запущен и заработает, просто отправьте ему запрос AJAX, чтобы проверить любой URL-адрес, указав URL-адрес в строке запроса как url(или как угодно вашему серверу). Вот код сервера в 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
источник