86

我正在使用Knockout.js绑定 iframesrc标记(这将针对用户进行配置)。

现在,如果用户配置了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 谢谢!!

4

9 回答 9

51

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

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

即使您对 google 进行了 ajax 调用,您也无法检查响应,因为浏览器强制执行同源策略。

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

因此,在您的服务器上......您的网络应用程序将向 www.google.com 发出请求,然后检查响应以查看它是否具有 X-Frame-Options 的标头参数。如果它确实存在,那么您知道 IFrame 会出错。

于 2013-09-06T19:47:09.940 回答
15

我认为您可以绑定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/

于 2013-08-31T20:57:51.840 回答
10

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

iframe.onload = function(){
   var that = $(this)[0];
   try{
        that.contentDocument;
   }
   catch(err){
        //TODO 
   }
}
于 2017-08-04T11:05:06.767 回答
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>
于 2018-09-22T16:32:46.887 回答
5

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

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

MSDN

于 2019-08-14T09:41:23.673 回答
3

更新: contentWindow.name 现在总是会在跨域帧上抛出错误。似乎唯一的方法是做这个服务器端(现在)。我编写了一个小型 cloudflare worker 来捕获远程 api 的标头,它可以在这里用来检查 X-Frame-Options。

在 iframe 中渲染之前要检查的示例代码:(jsfiddle:https ://jsfiddle.net/2gud39aw/2/ )

function checkUrlFrameOptions(apiurl){
  return fetch("https://header-inspector.repalash.workers.dev/?" + new URLSearchParams({
    'apiurl': apiurl,
    'headers': 'x-frame-options'
  }), {
    method: 'GET'
  }).then(r => r.json()).then(json => {
    let xFrameOp = (json.headers['x-frame-options'] || '').toLowerCase();
    // deny all requests
    if(xFrameOp==='deny') return false;
    // deny if different origin
    if(xFrameOp==='sameorigin' && json.origin !== location.origin) return false;
    return true;
  })
}

checkUrlFrameOptions("https://google.com").then((res)=>console.log("google.com can be loaded in iframe: ", res))
checkUrlFrameOptions("https://example.com").then((res)=>console.log("example.com can be loaded in iframe: ", res))

cloudflare worker 端点 ( https://header-inspector.repalash.workers.dev ) 仅用于测试,请勿在生产中使用。代码在:https ://gist.github.com/repalash/b1e778dbe3ac2e7149831c530a6535f9 可以直接部署为cloudflare worker

旧答案

这是一个简单的解决方案,在 Chrome 和 Safari 上进行了测试。

    const iframe = document.createElement('iframe')
    iframe.onload = function() {
        try {
            iframe.contentWindow.name
        } catch (e) {
            if (e.message.includes('cross-origin')) console.warn(e.message);
            else console.error(e.message);
        }
    }

    iframe.src = "https://google.com";

jsFiddle 演示:https ://jsfiddle.net/k5e1mg3t/5/

于 2021-06-07T16:40:57.210 回答
2

我遇到了类似的问题。我在不使用 onload 处理程序的情况下解决了它。我正在处理 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 Document 的头部。我有东西。CORS 没有停止加载,因为 CORS 错误显示空白页。如果 5 秒后没有出现任何错误(Cors 政策)等。显示合适的消息。谢谢。我希望它能解决你的问题。

于 2016-01-15T11:48:16.597 回答
0

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

但就我而言,我只需要发出一个跨域 http 请求,所以我使用脚本 src/onload/onerror 而不是 iframe。它运作良好。

于 2018-09-24T12:37:41.510 回答
0

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

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

于 2020-04-18T23:47:20.853 回答