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

xmakbtuz  于 2022-11-10  发布在  Go
关注(0)|答案(9)|浏览(144)

我正在使用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加载失败。我想要显示自定义消息。x1c 0d1x FIDDLE HERE
现在,如果我使用onload和onerror作为:-

<iframe id="browse" style="width:100%;height:100%" onload="alert('Done')" onerror="alert('Failed')"></iframe>

加载www.example.com可以正常工作w3schools.com但加载google.com就不行了。
第二:-如果我把它作为一个函数,并尝试像我在我的小提琴,它不工作。

<iframe id="browse" style="width:100%;height:100%" onload="load" onerror="error"></iframe>

我不知道如何让它运行并捕获错误。
编辑:-我已经看到想要调用一个函数,如果iframe不加载或加载的问题在堆栈溢出,但它显示错误的网站,可以加载在iframe。
此外,我已经调查了Stackoverflow iframe加载事件谢谢!!

bsxbgnwa

bsxbgnwa1#

由于浏览器设置的Same Origin Policy,您无法从客户端执行此操作。除了宽度和高度等基本属性外,您无法从iFrame中获取更多信息。
此外,谷歌在其响应报头中设置了SAMEORIGIN的“X-Frame-Options”。
即使你对谷歌做了一个 AJAX 调用,你也无法检查响应,因为浏览器强制执行同源策略。
因此,唯一的选择是从服务器发出请求,看看是否可以在IFrame中显示该站点。
因此,在您的服务器上,您的Web应用将向www.example.com发出请求www.google.com,然后检查响应是否包含X-Frame-Options的头参数。如果确实存在,则您知道IFrame将出错。

jxct1oxe

jxct1oxe2#

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

wqlqzqxt

wqlqzqxt3#

onload总是触发的,我用try catch块解决这个问题。当你试图获取contentDocument时,它会抛出一个异常。

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

bnlyeluc4#

这是对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>
8yoxcaq7

8yoxcaq75#

我用window.length解决了这个问题。但是用这个解决方案你可以得到当前的错误(X-Frame或404)。

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

MSDN

zyfwsgd6

zyfwsgd66#

**更新:**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 endpoint(https://header-inspector.repalash.workers.dev)仅用于测试,请勿在生产中使用。并且可以直接部署为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/

ppcbkaq5

ppcbkaq57#

我也遇到过类似的问题。我没有使用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文档的头部。如果有问题。CORS没有停止加载,因为CORS错误显示空白页。如果5秒后没有任何问题,则有一些错误(Cors策略)等。显示合适的消息。谢谢。希望它能解决您的问题。

ipakzgxi

ipakzgxi8#

我也有同样的问题,当iframe源代码加载错误时,chrome无法触发onerror。
但在我的例子中,我只需要发出一个跨域的http请求,所以我使用脚本src/onload/onerror代替iframe。

knsnq2tg

knsnq2tg9#

正如已接受的答案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)

相关问题