如果iframe src无法加载,则捕获错误。错误:-“拒绝在框架中显示“ http://www.google.co.in/”。”


79

Knockout.js用来绑定iframe广告src代码(这对于用户而言是可配置的)。

现在,如果用户配置了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中加载的网站的错误。

另外,我已经研究了加载事件上的Stackoverflow iframe, 谢谢!

Answers:


44

由于浏览器设置了“相同来源策略”,因此您将无法从客户端执行此操作。除了基本属性(例如其宽度和高度)之外,您将无法从iFrame获得很多信息。

此外,谷歌在其响应标头中设置SAMEORIGIN的“ X-Frame-Options ”。

即使您对Google进行了ajax调用,您也将无法检查响应,因为浏览器执行的是“同源政策”。

因此,唯一的选择是从服务器发出请求,以查看是否可以在IFrame中显示该站点。

因此,在您的服务器上。您的网络应用会向www.google.com发出请求,然后检查响应以查看其标题参数是否为X-Frame-Options。如果确实存在,则说明IFrame会出错。


Roblox使用iframe技巧<iframe src="roblox-player:foo">通过检测自定义URI处理程序来检测是否安装了游戏。检测到此iframe故障会触发“下载”按钮出现。那他们怎么办呢?
tresf

1
@QZ支持我不知道您在说什么。
伊万·拉尔森

1
@EvanLarsen我要提到一个非常流行的视频游戏,该游戏成功地使用了该<iframe>技术来启动(并且我希望检测到)在OS中注册的URI处理程序。这是一个免费游戏,您可以安装并自己查看。当您通过浏览器加入游戏时,它会使用iframe hack启动游戏。如果失败,则显示“下载”按钮。他们以某种方式知道URI是否被正确处理。我最初的猜测是捕获iframe错误,但是答案(以及我的测试)似乎表明这是不可能的。他们如何知道iframe何时发生故障?
tresf

这只是一个猜测,但我敢打赌,该网站只是在您本地计算机上调用自托管的Web应用程序。如果呼叫失败,则显示下载按钮。将游戏下载并安装到计算机上后,该网站将能够调用本地自托管网络应用。通过自我托管的Web应用程序。我的意思是,只有具有http端点的应用程序,任何知道它的网站都可以调用该应用程序。(即localhost:7845 / opengame / room / 2534
埃文·拉森

localhost:7845完全是假设。首先,它将遇到混合内容警告/错误(roblox.com使用HTTPS),其次,如果发生冲突,它将需要故障转移端口。用于启动该软件的技术是一种iframe。可以通过检查页面源来观察。当它无法启动该软件时,他们能够检测到它。这可以通过使用浏览器跟踪器ID的“电话回家” +超时方法来完成。我之所以这么说是因为这种iframe故障检测对于启动关联的应用程序很有用,但前提是可以检测到故障。
tresf

16

我认为您可以绑定loadiframe的事件,该事件在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/


50
嘿,只是看着小提琴-从来不会抛出错误。
vvohra87

12
我在Ubuntu和Chrome上-不管我在文本框中输入什么网址,它都说“完成”和“完成功能” :(
vvohra87 2013年

3
@IrvinDomininakaEdward:两个小提琴链接都无法正常工作……没有打开……您删除了小提琴吗?
Hitesh 2014年

9
减1,因为上面的注释指出:iframe加载失败时,提琴永远不会抛出预期的错误消息。这是因为即使不加载内容,iframe的加载事件也会触发。
CodeToad

3
这不应该是所选答案。以下是Evan提出的一种说法是正确的:浏览器安全性阻止了这一点。
斯科特·史密斯史密斯

8

onload将始终被触发,我尝试使用try catch块解决此问题。当您尝试获取contentDocument时将抛出异常。

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

1
到目前为止,这是我遇到过的最简单的方法,它实际上也适用!
西蒙·杰克逊

15
这也并不交叉领域的工作-它会抛出一个错误,无论哪种方式
Luoruize

对于我自己的域的iframe,这对我来说很有用。X-Frame-Options:SAMEORIGIN
Ryan

对我来说,即使iframe加载了内容,它也会引发相同的异常。您如何知道内容是否未加载?
leeCoder

我正要回答,以这种方式可以捕捉到该错误!但是你已经做到了!我正在以同样的方式处理同样的问题(并检查用户是否已重定向到我域中的某个页面)!我在搜索“ iframe中的处理错误”时遇到了这个问题,但是现在我在iframe中面临503错误!
Sampgun

8

这是对Edens答案的略微修改-对我来说,Chrome浏览器没有捕获该错误。尽管您仍然会在控制台中收到错误消息:“拒绝在框架中显示' https://www.google.ca/ ',因为它将'X-Frame-Options'设置为'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>

这导致出现“无法读取null的属性'location'”错误,that.contentDocument并且许多工作站点that.contentWindow在加载过程中仍会引发错误。
被遗弃的购物车,

1

我遇到了类似的问题。我没有使用onload handler来解决它。我在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秒钟后没有任何反应,则表明存在一些错误(Cors策略)等。显示适当的消息。谢谢。我希望它能解决您的问题。


2
Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "..." from accessing a cross-origin frame.-您确定它可以跨域工作吗?
火星罗伯逊

0

我有同样的问题,当iframe src加载错误时,chrome无法触发onerror。

但就我而言,我只需要发出跨域http请求,因此我使用脚本src / onload / onerror而不是iframe。运行良好。


0

我用解决了window.length。但是,使用此解决方案,您可以采取当前的错误(X帧或404)。

iframe.onload = event => {
   const isLoaded = event.target.contentWindow.window.length // 0 or 1
}

MSDN


0

如接受的答案https://stackoverflow.com/a/18665488/4038790中所述,您需要通过服务器进行检查。

由于没有可靠的方法可以在浏览器中检查此地址,因此建议您为自己构建一个快速的服务器端点,以用于检查是否可以通过iframe加载任何url。一旦服务器启动并运行,只需向其发送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)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.