检测 iframe 加载错误

Posted

技术标签:

【中文标题】检测 iframe 加载错误【英文标题】:detect iframe load error 【发布时间】:2012-10-24 17:03:29 【问题描述】:

我正在使用 src 属性将用户选择的页面加载到 iframe 中。如果加载失败,我想以对用户有意义的方式报告问题。根据http://www.w3schools.com/jsref/dom_obj_frame.asp,iframe 通常不支持 onerror。

该页面可能来自用户的域,而不是我的域,因此我无法查看 iframe 的内容。

如果加载成功,我可以设置一个超时并从我的 onload 处理程序中取消它,但是它需要一个很长的超时以避免错误的错误报告,同时我 iPhone 上的 Safari 显示了一个可能会混淆的警报用户。即使这对 Kindle Fire 浏览器也不起作用 - 无论加载是否成功,它都会向我的处理程序传递一个加载事件。

有什么事件可以用来检测失败吗?有什么方法可以抑制默认的 Safari 行为?有什么方法可以判断加载尝试是否失败? (如果我可以这样做,我可以使用更短的超时并轮询,直到加载尝试得到解决)。

我可以要求使用最新的浏览器,但希望有一个可以在尽可能多的智能手机和平板电脑之间移植的解决方案。

我已经测试了 AJAX Get 想法,但不幸的是它不起作用。跨域 AJAX Get 到任意 URI 会导致异常,无论目标是否存在以及是否可以加载到 iframe 中。

【问题讨论】:

我意识到这可能是不可能的。如果没有人发布让我做我想做的事情的解决方案,我计划将赏金奖励给最清晰、记录最完整的解释,通过证明这是不可能的来解决问题。 【参考方案1】:

您可以将您的 iframe 和/或 ajax 请求设置为始终调用您控制的页面(即:loader.php),通过 get 向用户请求的页面发送 loader.php。从 loader.php,使用 curl 甚至只是 file_get_contents 来获取外部页面。如果请求未能返回到 loader.php,您可以在那里检查错误,并返回您希望 iframe 显示的任何内容。

虽然我的示例引用了 php,但各种脚本语言都支持 curl。它可能比您可能拥有的其他解决方案更复杂,但可以让您访问响应标头以及排除页面加载失败的原因。

【讨论】:

听起来很有希望。我试试看。 在一篇文章中它被称为a Web Proxy。如果您这样做,您可以want to consider whitelisting 域。 我相信会有这样的解决方案,而且当前的赏金期即将结束,所以我决定授予它赏金。但是,这不是我的问题的完整解决方案,我还在寻找想法,所以我没有接受答案。 谢谢!你有机会测试这种方法吗?如果是这样,你遇到了什么?【参考方案2】:

正如您所暗示的,当您尝试在 iframe 中查询位于单独域中的任何内容时,您将面临同源策略类型限制。

在将 iframe 的 URL 传递到框架的 src 之前,您可以向它发出 AJAX GET 请求。如果您没有从 AJAX 调用返回 HTTP 200 响应,那么该网站也将无法在框架内加载。

这将增加整个过程的开销,并且仅在您检查 是否 iframe 的文档是有效的真实 URL 时才有用。如果您需要知道何时 iframe 文档已完全加载,这将无济于事。

如果您需要知道 iframe 何时加载,并且它位于外部域中,那么我相信您别无选择,只能要求将一些代码添加到这些外部站点以通知父页面它们'已成功加载。

或者,如果这样做有意义,请让最终用户单击链接以标记内容未正确加载。

【讨论】:

预测试是一个有趣的想法。我会尝试一下。如果加载成功,则没有问题。 iframe 确实支持 onload,到目前为止我尝试过的所有浏览器都会在成功加载时调用我的 onload 处理程序。 我刚刚有了另一个想法。也许我可以先启动 iframe 加载,然后稍等片刻。如果我在超时之前得到 onload,一切都很好。如果没有,尝试AJAX GET测试,如果失败则报告失败,如果成功则返回等待更长的时间。对于页面快速加载的正常情况,这将尽可能快。缺点是我仍然会在失败时收到 Safari 警报。 是的,这将回答这个问题,“它是关闭/丢失,还是非常缓慢?” 不幸的是,由于跨域问题,它不起作用。我在发送调用中遇到异常。至少在 Safari 上,无论目标是否存在,异常都是相同的。很好的尝试。【参考方案3】:

聚会迟到了,但我已经成功了:

起初,我想像其他人一样进行 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.log("iframe failed to load");
    
;
xhttp.open("GET", url, true);
xhttp.send();

编辑: 所以这个方法工作正常,除了它有很多假阴性(拿起很多会在 iframe 中显示的东西)由于跨域恶意。我解决这个问题的方法是在服务器上执行 CURL/Web 请求,然后检查响应标头 a) 网站是否存在,b) 标头是否设置了 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 加载错误的主要内容,如果未能解决你的问题,请参考以下文章

检测 iframe 何时开始加载新 URL

检测 Iframe 内容何时加载(跨浏览器)

检测 iframe src 是不是可显示

检测动态加载的 iframe

iframe内部不会长时间显示检测到iframe

如何在 Flask 中重新加载有错误的 fancybox iframe 表单