检测无法加载iframe的内容

Dan*_*idy 53 html javascript xulrunner frames firefox-addon

我可以使用load事件检测何时加载了iframe的内容.不幸的是,就我的目的而言,这有两个问题:

  • 如果加载页面时出错(404/500等),则永远不会触发load事件.
  • 如果某些映像或其他依赖项无法加载,则会像往常一样触发load事件.

是否有某种方法可以确定是否发生上述任何一种错误?

我正在编写一个基于Mozilla/XULRunner的半网络半桌面应用程序,因此欢迎只在Mozilla中运行的解决方案.

spl*_*tne 14

如果您可以控制iframe页面(并且页面位于同一域名中),则策略可以如下所示:

  • 在父文档中,初始化变量 var iFrameLoaded = false;
  • 加载iframe文档时,在父项中设置此变量以true从iframe文档调用父项的函数(setIFrameLoaded();(例如).
  • iFrameLoaded使用该timer对象检查该标志(将计时器设置为您的首选超时限制) - 如果该标志仍为false,则可以判断iframe未定期加载.

我希望这有帮助.

  • 1)为什么要麻烦添加到iframe页面?我可以像setTimeout一样轻松地使用setTimeout.2)这不能可靠地检测负载是否失败或原因,只是它是否在一个时间限制内成功.3)不检测页面依赖性无法加载的情况. (6认同)
  • 不同的资源将在不同的时间范围内加载。这种不可预测性会扼杀你的方法 Daniel Cassidy,因为你必须允许相当长的超时时间。与此同时,短暂的加载错误只会挂在屏幕上,直到计时器假设资源加载失败并处理错误。 (2认同)

Chr*_*ris 8

我最近遇到了这个问题,不得不求助于在父页面上设置Javascript轮询操作(包含IFRAME标记).此JavaScript函数检查IFRAME的内容,以查找仅应存在于GOOD响应中的显式元素.当然,这假定您不必处理违反"同源政策"的问题.

而不是检查可能从许多不同的网络资源生成的所有可能的错误.我只是检查了一个我知道应该是一个良好响应的恒定正元素.

在预定的时间和/或尝试检测到预期元素的失败后,JavaScript会修改IFRAME的SRC属性(从我的Servlet请求)用户友好错误页面,而不是显示典型的HTTP错误消息.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");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

}


Дми*_*лев 7

这是一个很晚的答案,但我会把它留给需要它的人。

任务: 加载 iframe 跨域内容,onLoaded在成功和onError加载错误时发出

这是我可以开发的最跨浏览器来源的独立解决方案。但首先,我将简要介绍我采用的其他方法以及它们为什么不好。

1. iframe这对我来说有点震惊,iframe 只有onload事件,并且在加载和出错时调用它,无法知道它是否出错。

2. performance.getEntriesByType('resource')。此方法返回加载的资源。听起来像我们需要的。但是很遗憾,firefox 总是在资源数组中添加 Resource,无论加载还是失败。无法通过Resource实例知道它是否成功。照常。顺便说一下,这个方法在 ios<11 中不起作用。

3. 脚本我尝试使用<script>标签加载 html 。发射onloadonerror正确的,遗憾的是,仅适用于Chrome。

当我准备放弃时,我的老同事告诉我关于 html4 tag <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;
Run Code Online (Sandbox Code Playgroud)

在此之后,我们可以设置一些属性,<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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,困难的部分。像许多相同的元素一样,<object>没有回调规范,因此每个浏览器的行为都不同。

  • 。在错误和加载时发出load事件。
  • 火狐。发射loaderror正确。
  • 野生动物园。什么都不发出....

似乎与iframe, getEntriesByType, script....没有什么不同。但是,我们有原生浏览器回退!所以,因为我们直接设置了fallback(innerHtml),所以我们可以判断是否<object>加载了

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

/**
 * Firefox on error
 */
obj.onerror = function() {
    onError();
};
Run Code Online (Sandbox Code Playgroud)

但是如何处理 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;
}
Run Code Online (Sandbox Code Playgroud)

是的……没那么快。问题是,<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);
Run Code Online (Sandbox Code Playgroud)

好了,开始加载

document.body.appendChild(obj);
Run Code Online (Sandbox Code Playgroud)

这就是全部。我试图详细解释代码,所以它可能看起来不那么愚蠢。

PS WebDev 很烂