如果 iframe src 加载失败,捕捉错误。错误:-“拒绝在帧中显示‘ http://www.google.co.in/’...”

我正在使用 Knockout.js绑定 iframe src标记(这对于 User 是可配置的)。

现在,如果用户已经配置了 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 加载失败。我想显示 自定义信息Screenshot of console when I get error 小提琴

现在,如果我将 onload 和 onerror 用作:-

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

它可以很好地加载 w3school. com,但是不能加载 google.com。

其次:-如果我把它作为一个函数,并尝试像我已经在我的小提琴,它不工作。

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

我不知道如何让它运行并捕获错误。

编辑:-我已经看到了在堆栈溢出的 想要调用一个函数,如果 iframe 没有加载或加载的问题,但它显示的网站错误,可以在 iframe 加载。

此外,我还查看了关于加载事件的 Stackoverflow iframe 谢谢!

169434 次浏览

I think that you can bind the load event of the iframe, the event fires when the iframe content is fully loaded.

At the same time you can start a setTimeout, if the iFrame is loaded clear the timeout alternatively let the timeout fire.

Code:

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);
}));


});

Demo: http://jsfiddle.net/IrvinDominin/QXc6P/

Second problem

It is because you miss the parens in the inline function call; try change this:

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

into this:

<iframe id="browse" style="width:100%;height:100%" onload="load('Done func');" onerror="error('failed function');"></iframe>

Demo: http://jsfiddle.net/IrvinDominin/ALBXR/4/

You wont be able to do this from the client side because of the Same Origin Policy set by the browsers. You wont be able to get much information from the iFrame other than basic properties like its width and height.

Also, google sets in its response header an 'X-Frame-Options' of SAMEORIGIN.

Even if you did an ajax call to google you wont be able to inspect the response because the browser enforcing Same Origin Policy.

So, the only option is to make the request from your server to see if you can display the site in your IFrame.

So, on your server.. your web app would make a request to www.google.com and then inspect the response to see if it has a header argument of X-Frame-Options. If it does exist then you know the IFrame will error.

I faced similar problem. I solved it without using onload handler.I was working on AngularJs project so i used $interval and $ timeout. U can also use setTimeout and setInterval.Here's the code:

 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);
});

Every 0.4 Seconds keep checking the head of iFrame Document. I somthing is present.Loading was not stopped by CORS as CORS error shows blank page. If nothing is present after 5 seconds there was some error (Cors policy) etc.. Show suitable message.Thanks. I hope it solves your problem.

The onload will always be trigger, i slove this problem use try catch block.It will throw an exception when you try to get the contentDocument.

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

This is a slight modification to Edens answer - which for me in chrome didn't catch the error. Although you'll still get an error in the console: "Refused to display 'https://www.google.ca/' in a frame because it set 'X-Frame-Options' to 'sameorigin'." At least this will catch the error message and then you can deal with it.

 <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>

I solved it with window.length. But with this solution you can take current error (X-Frame or 404).

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

MSDN

As explained in the accepted answer, https://stackoverflow.com/a/18665488/4038790, you need to check via a server.

Because there's no reliable way to check this in the browser, I suggest you build yourself a quick server endpoint that you can use to check if any url is loadable via iframe. Once your server is up and running, just send a AJAX request to it to check any url by providing the url in the query string as url (or whatever your server desires). Here's the server code in 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)

Update: contentWindow.name will now always throw an error on cross-origin frames. Seems like the only way is to do this server side (for now). I have written a small cloudflare worker to capture headers for remote apis and it can be used here to check for X-Frame-Options.

Sample code to check before rendering in 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))

The cloudflare worker endpoint ( https://header-inspector.repalash.workers.dev ) is just for testing, don't use this in production. The code is available at: https://gist.github.com/repalash/b1e778dbe3ac2e7149831c530a6535f9 and can be deployed directly as a cloudflare worker

OLD Answer

Here's a simple solution, tested on Chrome and 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 demo: https://jsfiddle.net/k5e1mg3t/5/