如何识别网页是在ifram中加载还是直接加载到浏览器窗口中?

我正在编写一个基于ifram的facebook应用程序。现在我想使用相同的html页面来渲染普通网站以及facebook内的画布页面。我想知道我是否可以确定该页面是在ifram内加载的还是直接在浏览器中加载的?

414409 次浏览

由于同源政策,浏览器可以阻止对window.top的访问。IE错误也会发生。这是工作代码:

function inIframe () {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}

topself都是window对象(与parent一起),因此您正在查看您的窗口是否是顶部窗口。

罗博格是对的,但我想补充一点。

在IE7/IE8中,当Microsoft将Tabs添加到他们的浏览器时,他们破坏了一件事,如果你不小心,它会对你的JS造成严重破坏。

想象一下这个页面布局:

MainPage.html
IframedPage1.html   (named "foo")
IframedPage2.html   (named "bar")
IframedPage3.html (named "baz")

现在在框架“baz”中,您单击链接(没有目标,在“baz”框架中加载),它可以正常工作。

如果加载的页面,我们称之为special.html,使用JS检查“it”是否有一个名为“bar”的父框架,它将返回true(预期)。

现在假设special.html页面在加载时检查父框架(是否存在及其名称,如果它是“bar”,它会在bar框架中重新加载自己。

if(window.parent && window.parent.name == 'bar'){
window.parent.location = self.location;
}

到目前为止一切顺利。现在bug。

比方说,而不是像往常一样点击原始链接,并在“baz”框架中加载special.html页面,您中键单击它或选择在新选项卡中打开它。

当新选项卡加载(根本没有父框架!IE将进入页面加载的无尽循环!时,因为IE“复制”了JavaScript中的框架结构,使得新选项卡确实有一个父级,并且该父级具有名称“bar”。

好消息是,检查:

if(self == top){
//this returns true!
}

在那个新选项卡中确实返回true,因此您可以测试这种奇怪的情况。

由于您是在facebook应用程序的上下文中询问,因此您可能需要考虑在发出初始请求时在服务器上检测到此情况。Facebook将传递一堆查询字符串数据,包括从ifram调用的fb_sig_user键。

由于您可能需要在应用程序中检查和使用此数据,因此请使用它来确定要呈现的适当上下文。

使用此javascript函数作为如何完成此操作的示例。

function isNoIframeOrIframeInMyHost() {
// Validation: it must be loaded as the top page, or if it is loaded in an iframe
// then it must be embedded in my own domain.
// Info: IF top.location.href is not accessible THEN it is embedded in an iframe
// and the domains are different.
var myresult = true;
try {
var tophref = top.location.href;
var tophostname = top.location.hostname.toString();
var myhref = location.href;
if (tophref === myhref) {
myresult = true;
} else if (tophostname !== "www.yourdomain.com") {
myresult = false;
}
} catch (error) {
// error is a permission error that top.location.href is not accessible
// (which means parent domain <> iframe domain)!
myresult = false;
}
return myresult;
}

接受的答案在Firefox 6.0扩展(Addon-SDK 1.0)的内容脚本中对我不起作用:Firefox在每个顶级窗口和所有ifram中执行内容脚本。

在内容脚本中,我得到以下结果:

 (window !== window.top) : false
(window.self !== window.top) : true

这个输出的奇怪之处在于,无论代码是在ifram还是在顶级窗口中运行,它总是相同的。

另一方面,GoogleChrome似乎只在顶级窗口中执行一次我的内容脚本,所以上面的操作根本不起作用。

在两种浏览器的内容脚本中,最终对我有效的是:

 console.log(window.frames.length + ':' + parent.frames.length);

如果没有iframe,则打印0:0,在包含一个帧的顶层窗口中打印1:1,在文档的唯一ifram中打印0:1

这允许我的扩展在两个浏览器中确定是否存在任何iFrame,并且在Firefox中确定它是否在其中一个iFrame中运行。

这是一段我用过几次的古老代码:

if (parent.location.href == self.location.href) {
window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}

我正在使用这个:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
if (window.frames.length != parent.frames.length) { page loaded in iframe }

但只有当您的页面和将您加载到ifram中的页面中的ifram数量不同时。在您的页面中不要制作ifram以100%保证此代码的结果

在每一页中写这个javascript

if (self == top)
{ window.location = "Home.aspx"; }

然后它会自动重定向到主页。

如果您想知道用户是从Facebook页面选项卡还是画布访问您的应用程序,请检查签名请求。如果您没有得到它,可能用户没有从Facebook访问。 确保确认signed_request字段结构和字段内容。

使用php-sdk,您可以像这样获得签名请求:

$signed_request = $facebook->getSignedRequest();

您可以在此处阅读有关签名请求的更多信息:

在这里:

当在与父框架同源的ifram中时,window.frameElement方法返回窗口嵌入的元素(例如iframeobject)。否则,如果在顶级上下文中浏览,或者父框架和子框架有不同的源,它将计算为null

window.frameElement
? 'embedded in iframe or object'
: 'not embedded or cross-origin'

这是一个超文本标记语言标准,在所有现代浏览器中都有基本支持。

我实际上曾经检查过window.parent,它对我有用,但最近windows是一个循环对象,并且总是有一个父键,ifram或没有ifram。

由于评论建议与window.parent作品进行比较。不确定如果ifram与父网页完全相同,这是否有效。

window === window.parent;

我不确定这个示例如何适用于旧的Web浏览器,但我将其用于IE,Firefox和Chrome没有问题:

var iFrameDetection = (window === window.parent) ? false : true;

最适合现在的旧版浏览器框架破坏脚本

其他解决方案对我不起作用。这个适用于所有浏览器:

防御点击劫持的一种方法是在每个不应该框架的页面中包含一个“帧断开器”脚本。以下方法论将防止网页被框架化,即使在不支持X-Frame-Options-Header的旧浏览器中也是如此。

在文档HEAD元素中,添加以下内容:

<style id="antiClickjack">body{display:none !important;}</style>

首先将ID应用于style元素本身:

<script type="text/javascript">
if (self === top) {
var antiClickjack = document.getElementById("antiClickjack");
antiClickjack.parentNode.removeChild(antiClickjack);
} else {
top.location = self.location;
}
</script>

这样,所有内容都可以在文档HEAD中,并且您的API中只需要一个方法/taglib。

参考:https://www.codemagi.com/blog/post/194

这对我来说是最简单的解决方案。

    <p id="demofsdfsdfs"></p>


<script>


if(window.self !== window.top) {


//run this code if in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "in frame";


}else{


//run code if not in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "no frame";
}


</script>
if ( window !== window.parent )
{
// The page is in an iframe
}
else
{
// The page is not in an iframe
}
function amiLoadedInIFrame() {
try {
// Introduce a new propery in window.top
window.top.dummyAttribute = true;
// If window.dummyAttribute is there.. then window and window.top are same intances
return !window.dummyAttribute;
} catch(e) {
// Exception will be raised when the top is in different domain
return true;
}
}

接下来是@马尼奥斯所说的,这里是他的答案的代码实现。

constructor() {
let windowLen = window.frames.length;
let parentLen = parent.frames.length;


if (windowLen == 0 && parentLen >= 1) {
this.isInIframe = true
console.log('Is in Iframe!')
} else {
console.log('Is in main window!')
}
}