Помилка лову, якщо 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 не вдається завантажити. Я хочу відобразити власне повідомлення . Знімок екрана консолі при появі помилки СУПИТИ ТУТ

Тепер, якщо я використовую 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.

Крім того, я розглянув iframe Stackoverflow при завантаженні події Дякую !!

Відповіді:


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 Я не маю уявлення про що ви говорите.
Еван Ларсен

1
@EvanLarsen Я згадую дуже популярну відеоігру, яка успішно використовує <iframe>техніку для запуску (і я сподівався виявити) обробника URI, зареєстрованого в ОС. Це безкоштовна гра, ви можете встановити її і переконатися самі. Коли ви приєднуєтесь до гри через браузер, він використовує вбудований хакер для запуску гри. Якщо це не вдається, вони показують кнопку "завантажити". Якось вони знають, чи правильно оброблявся 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

12
Я на Ubuntu та Chrome - незалежно від того, яку URL-адресу я вклав у текстове поле, там написано "готово" та "зроблено
функцію

3
@IrvinDomininakaEdward: обидва скрипкові посилання не працюють ... не відкриваються ... ви видалили скрипку?
Хітеш

10
мінус 1, оскільки, як зазначено в коментарях вище: скрипка ніколи не видає очікуваного повідомлення про помилку, коли iframe не вдається завантажити. це тому, що подія завантаження iframe спрацьовує навіть тоді, коли він не завантажує вміст.
CodeToad

3
Це не повинна бути обрана відповідь. Наведений нижче Еван правильний: безпека браузера не дозволяє виявити це.
Скотт Сміт,

9

Onload завжди буде тригером, я використовую цю проблему, використовуючи try catch block. Це викличе виняток при спробі отримати contentDocument.

iframe.onload = function(){
   var that = $(this)[0];
   try{
        that.contentDocument;
   }
   catch(err){
        //TODO 
   }
}

1
Це найпростіший спосіб, з яким я досі стикався, і він насправді теж працює!
Саймон Джексон,

15
Це також не працює для міждоменів - в будь-якому випадку з’явиться помилка
Luoruize

Це спрацювало для мене, для iframe мого власного домену. X-Frame-Options: SAMEORIGIN
Райан

для мене він видає той самий виняток, навіть коли iframe завантажує вміст. як дізнатися, чи не завантажується вміст?
leeCoder

Я збирався відповісти, що можна вловити цю помилку таким чином! Але ти вже зробив! Я обробляю ту саму точну проблему (а також перевіряю, чи було перенаправлено користувача на певну сторінку в моєму домені) таким чином! Я зіткнувся з цим запитанням у пошуках "обробки помилок у iframe", але зараз я стикаюся з помилкою 503 всередині iframe!
Sampgun

8

Це невелика модифікація відповіді Edens - яка для мене в chrome не виявила помилки. Хоча ви все одно отримаєте помилку в консолі: "Відмовлено відображати" https://www.google.ca/ "у фреймі, оскільки для параметра" Параметри X-Frame "встановлено значення" 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>

Це призводить до помилки "неможливо прочитати властивість 'location' null", that.contentDocumentі багато робочих сайтів все одно видаватимуть помилку that.contentWindowпід час завантаження.
Покинутий

1

Я зіткнувся з подібною проблемою. Я вирішив це, не використовуючи обробник onload. Я працював над проектом AngularJs, тому використовував $ interval та $ timeout. Ви також можете використовувати 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 секунд нічого немає, сталася помилка (політика Корсу) тощо. Показати відповідне повідомлення. Дякую. Сподіваюся, це вирішить вашу проблему.


2
Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "..." from accessing a cross-origin frame.- Ви впевнені, що він працює міждоменним?
Марс Робертсон,

0

У мене така сама проблема, Chrome не може запустити onerror, коли помилка завантаження 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


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)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.