it-swarm.cn

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

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

515
akshat

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

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

topself都是window对象(以及parent),所以你看到你的窗口是否是顶窗。

962
Greg

window.frameElement 方法返回嵌入窗口的元素(例如iframeobject),如果在顶级上下文中浏览则返回null

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

这是一个 HTML标准 在所有现代浏览器中都有基本支持。

78
Konstantin Smolyanin

RoBorg是正确的,但我想添加一个旁注。

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

想象一下这个页面布局:

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

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

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

现在让我们说,在加载时,special.html页面检查父框架(对于存在及其名称,如果它是“bar”,它会在条形框架中重新加载。

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

到现在为止还挺好。现在来了错误。

让我们说,不是像平常一样点击原始链接,而是在“baz”框架中加载special.html页面,您可以在其中间单击它或选择在新标签中打开它。

当新的标签加载时( 完全没有父框架! IE将进入无限循环的页面加载! 因为IE“复制”JavaScript中的帧结构,使得新选项卡具有父项,并且该父项具有名称“bar”。

好消息是检查:

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

在新的选项卡确实返回true,因此您可以测试这个奇怪的条件。

25
scunliffe

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

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

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

关于此输出的奇怪之处在于,无论代码是在iframe内还是在顶级窗口中运行,它始终都是相同的。

另一方面,谷歌浏览器似乎只在顶级窗口中执行一次我的内容脚本,因此上述内容根本不起作用。

在两种浏览器的内容脚本中最终为我工作的是:

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

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

这允许我的扩展程序在两个浏览器中确定是否存在任何iframe,另外在Firefox中如果它在其中一个iframe中运行。

18
magnoz

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

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

我正在使用这个:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
5
mikewolf78

使用此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;
}
2
Rolf

我实际上用来检查window.parent它对我有用,但最近窗口是一个循环对象,并且总是有一个父键,iframe或没有iframe。

由于评论建议与window.parent相比很难。如果iframe与父网页完全相同,则不确定这是否有效。

window === window.parent;
1
Jabran Saeed

最好的现在Legacy浏览器框架打破脚本

其他解决方案对我没用。这适用于所有浏览器:

防止点击劫持的一种方法是在每个页面中包含一个不应框架的“框架破坏”脚本。以下方法将阻止网页即使在不支持X-Frame-Options-Header的旧版浏览器中也被加框。

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

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

首先将一个ID应用于样式元素本身:

<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

1
Albert Olivé

由于您在Facebook应用程序的上下文中询问,您可能需要考虑在初始请求发生时在服务器上检测到这一点。如果从iframe调用它,Facebook将传递一堆查询字符串数据,包括fb_sig_user键。

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

1
HectorMac

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

    <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>
0
Alex Roseland