16

我正在使用 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 中。

4

3 回答 3

10

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

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

于 2012-11-07T16:52:58.123 回答
2

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

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

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

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

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

于 2012-11-05T00:12:01.250 回答
-1

派对迟到了,但我设法破解了它:

起初,我想像其他人一样进行 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();
});
于 2017-08-22T15:12:19.437 回答