Обнаружить сбой при загрузке содержимого iframe

Я могу определить, когда содержимое iframe загружено, с помощью события нагрузка. К сожалению, для моих целей здесь есть две проблемы:

  • Если при загрузке страницы возникает ошибка (404/500 и т. д.), Событие загрузки никогда не запускается.
  • Если не удалось загрузить некоторые изображения или другие зависимости, событие загрузки запускается как обычно.

Есть ли способ надежно определить, произошла ли какая-либо из вышеперечисленных ошибок?

Я пишу полу-веб-приложение для полу-рабочего стола на основе Mozilla / XULRunner, поэтому приветствуются решения, которые работают только в Mozilla.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
57
0
44 081
6

Ответы 6

Если у вас есть контроль над страницей iframe (и страницы находятся на одном доменном имени), стратегия может быть следующей:

  • В родительском документе инициализируйте переменную var iFrameLoaded = false;
  • Когда документ iframe загружен, установите эту переменную в родительском элементе на true, вызывая из документа iframe, например, родительскую функцию (setIFrameLoaded();).
  • проверьте флаг iFrameLoaded с помощью объекта timer (установите таймер на предпочитаемый вами предел времени ожидания) - если флаг все еще ложен, вы можете сказать, что iframe не загружался регулярно.

Надеюсь, это поможет.

1) Зачем добавлять JavaScript на страницу iframe? С таким же успехом я мог бы использовать setTimeout вместе с событием загрузки. 2) Это не позволяет надежно определить, произошел ли сбой загрузки или почему, просто удастся ли она выполнить в течение установленного времени. 3) Не определяет случай, когда зависимости страниц не загружаются.

Daniel Cassidy 17.12.2008 23:17

Разные ресурсы будут загружаться в разные периоды времени. Эта непредсказуемость убьет ваш подход Дэниела Кэссиди, поскольку вам придется предусмотреть достаточно длительный тайм-аут. Тем временем кратковременные ошибки загрузки будут просто отображаться на экране до тех пор, пока таймер не примет решение, что ресурс не удалось загрузить, и не обработает ошибку.

seebiscuit 23.10.2015 17:46

Недавно у меня возникла эта проблема, и мне пришлось прибегнуть к настройке действия Javascript Polling на родительской странице (которая содержит тег IFRAME). Эта функция JavaScript проверяет содержимое IFRAME на наличие явных элементов, которые должны существовать только в ХОРОШИМ ответе. Это, конечно, предполагает, что вам не нужно иметь дело с нарушением «политики одного и того же происхождения».

Вместо проверки всех возможных ошибок, которые могут быть сгенерированы множеством различных сетевых ресурсов ... Я просто проверил один постоянный положительный элемент (ы), который, как я знаю, должен быть в хорошем ответе.

После заранее определенного времени и / или количества неудачных попыток обнаружить ожидаемый элемент (ы), JavaScript изменяет атрибут SRC IFRAME (для запроса от моего сервлета) удобную для пользователя страницу ошибки вместо отображения типичного сообщения HTTP ERROR. . JavaScript также может легко изменить атрибут SRC, чтобы сделать совершенно другой запрос.

function checkForContents(){
var contents=document.getElementById('myiframe').contentWindow.document
if (contents){
    alert('found contents of myiframe:' + contents);
    if (contents.documentElement){
        if (contents.documentElement.innerHTML){
            alert("Found contents: " +contents.documentElement.innerHTML);
            if (contents.documentElement.innerHTML.indexOf("FIND_ME") > -1){
                openMediumWindow("woot.html", "mypopup");
            }
        }
    }
}

}

Я думаю, что событие pageshow запускается для страниц с ошибками. Или, если вы делаете это из Chrome, тогда вы проверяете запрос слушателя прогресса, чтобы узнать, является ли он каналом HTTP, и в этом случае вы можете получить код состояния.

Что касается зависимостей страниц, я думаю, вы можете сделать это только из chrome, добавив прослушиватель событий onerror, и даже тогда он будет находить ошибки только в элементах, а не в фонах CSS или других изображениях.

Имейте идентификатор для самого верхнего (основного) элемента на странице, которая загружается в ваш iframe.

в обработчике загрузки вашего iframe проверьте, возвращает ли getElementById () ненулевое значение. Если это так, iframe загружен успешно. иначе это не удалось.

в этом случае поместите frame.src = "about: blank". Перед этим обязательно снимите грузоподъемное устройство.

что, если у нас нет контроля над страницей, которую мы загружаем. тогда как справиться с этой ситуацией ??

PHP_RIDER 17.12.2015 15:18

Точно не отвечает на ваш вопрос, но мой поиск ответа привел меня сюда, поэтому я отправляю сообщение на тот случай, если у кого-то еще есть аналогичный мне запрос.

Он не совсем использует событие загрузки, но он может определить, доступен ли веб-сайт и может ли он быть вызван (если это так, то iFrame, теоретически, должен загружаться).

Сначала я подумал сделать вызов AJAX, как и все остальные, за исключением того, что у меня изначально это не сработало, так как я использовал jQuery. Он отлично работает, если вы выполняете XMLHttpRequest:

var url = http://url_to_test.com/
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status != 200) {
        console.info("iframe failed to load");
    }
};
xhttp.open("GET", url, true);
xhttp.send();

Редактировать:
Таким образом, этот метод работает нормально, за исключением того, что он имеет много ложных отрицаний (собирает много вещей, которые будут отображаться в iframe) из-за маларкости перекрестного происхождения. Способ, которым я обошел это, заключался в том, чтобы выполнить CURL / веб-запрос на сервере, а затем проверить заголовки ответа на: а) если веб-сайт существует, и б) если в заголовках установлен x-frame-options.

Это не проблема, если у вас есть собственный веб-сервер, так как вы можете сделать для него свой собственный вызов API.

Моя реализация в node.js:

app.get('/iframetest',function(req,res){ //Call using /iframetest?url=url - needs to be stripped of http:// or https://
   var url = req.query.url; 
    var request = require('https').request({host: url}, function(response){ //This does an https request - require('http') if you want to do a http request
        var headers = response.headers;
        if (typeof headers["x-frame-options"] != 'undefined') {
            res.send(false); //Headers don't allow iframe
        } else {
            res.send(true); //Headers don't disallow iframe
        }
    });
    request.on('error',function(e){
       res.send(false); //website unavailable
    });
    request.end();
});

Это очень поздний ответ, но я оставлю его тем, кому он нужен.

Задача:загружать содержимое iframe из разных источников, выдавать onLoaded в случае успеха и onError при ошибке загрузки.

Это наиболее кроссбраузерное решение, независимое от происхождения, которое я мог разработать. Но сначала я кратко расскажу о других подходах, которые у меня были, и о том, почему они плохие.

1. iframe Меня немного шокировало, что iframe имеет только событие onload и вызывается при загрузке и при ошибке, нет возможности узнать, ошибка это или нет.

2. performance.getEntriesByType ('ресурс'). Этот метод возвращает загруженные ресурсы. Похоже на то, что нам нужно. Но какой позор, firefox всегда добавляет ресурс в массив ресурсов, независимо от того, загружен он или вышел из строя. По экземпляру Resource невозможно узнать, был ли он успешным. По-прежнему. Кстати, в ios <11 этот способ не работает.

3. сценарий Я пытался загрузить html с помощью тега <script>. Выдает onload и onerror правильно, к сожалению, только в Chrome.

И когда я был готов сдаться, мой старший коллега рассказал мне о html4-теге <object>. Он похож на тег <iframe>, за исключением того, что у него есть резервные варианты, когда контент не загружен. Это похоже на то, что нам нужно! К сожалению, это не так просто, как кажется.

РАЗДЕЛ КОДА

var obj = document.createElement('object');

// we need to specify a callback (i will mention why later)
obj.innerHTML = '<div style = "height:5px"><div/>'; // fallback

obj.style.display = 'block'; // so height=5px will work
obj.style.visibility = 'hidden'; // to hide before loaded

obj.data = src;

После этого мы можем установить некоторые атрибуты для <object>, как мы хотели сделать с iframe. Единственное отличие, мы должны использовать <params>, а не атрибуты, а их имена и значения идентичны.

for (var prop in params) {
    if (params.hasOwnProperty(prop)) {
        var param = document.createElement('param');
        param.name = prop;
        param.value = params[prop];

        obj.appendChild(param);
    }
}

А теперь самое сложное. Как и многие подобные элементы, <object> не имеет спецификаций для обратных вызовов, поэтому каждый браузер ведет себя по-разному.

  • Хром. При ошибке и при загрузке выдает событие load.
  • Fire Fox. Правильно излучает load и error.
  • Сафари. Ничего не излучает ....

Похоже, ничем не отличается от iframe, getEntriesByType, script .... Но у нас есть запасной вариант для браузера! Итак, поскольку мы устанавливаем резервный вариант (innerHtml) напрямую, мы можем определить, загружен ли <object> или нет.

function isReallyLoaded(obj) {
    return obj.offsetHeight !== 5; // fallback height
}
/**
 * Chrome calls always, Firefox on load
 */
obj.onload = function() {
    isReallyLoaded(obj) ? onLoaded() : onError();
};

/**
 * Firefox on error
 */
obj.onerror = function() {
    onError();
};

Но что делать с Safari? Старый добрый setTimeout.

var interval = function() {
    if (isLoaded) { // some flag
        return;
    }

    if (hasResult(obj)) {
        if (isReallyLoaded(obj)) {
            onLoaded();
        } else {
            onError();
        }
    }

    setTimeout(interval, 100);
};

function hasResult(obj) {
    return obj.offsetHeight > 0;
}

Ага .... не так быстро. Дело в том, что <object> в случае сбоя не упоминается в спецификациях:

  1. Пытаюсь загрузить (размер = 0)
  2. Не удается (размер = любой) действительно
  3. Резервный (размер = как в innnerHtml)

Итак, код нуждается в небольшом улучшении

var interval = function() {
    if (isLoaded) { // some flag
        return;
    }

    if (hasResult(obj)) {
        if (isReallyLoaded(obj)) {
            interval.count++;
            // needs less then 400ms to fallback
            interval.count > 4 && onLoadedResult(obj, onLoaded);
        } else {
            onErrorResult(obj, onError);
        }
    }

    setTimeout(interval, 100);
};
interval.count = 0;

setTimeout(interval, 100);

Ну а для начала загрузки

document.body.appendChild(obj);

Это все. Я попытался объяснить код во всех деталях, так что это может показаться не таким уж глупым.

P.S. WebDev отстой

Другие вопросы по теме