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


Answers:


1106

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

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

topself都是window对象(以及parent),因此您正在查看窗口是否是顶部窗口。


4
这似乎在Firefox中可以正常工作。它也可以在其他浏览器中使用吗?
akshat

5
在iframe中有一个内含iframe的页面,以便从子iframe进行测试,以了解是否将我的父iframe嵌入了该页面,我使用了if(parent === top)
sglessard 2012年

7
@sglessard如果孩子页面和父母来自不同的域,然后Firefox会抱怨的同源策略(www.w3.org/Security/wiki/Same_Origin_Policy)和代码将无法正常工作
GAURANG Jadia

18
这对我来说适用于IE 11、10和9。它还适用于FF和Opera,当然也适用于Chrome。我还没有遇到任何问题。
jeremysawesome

4
对于那些仍然摇摆于1995年的高科技最新的,window.self !== window.top返回true从内容中运行时frame或者 iframe
Jeromy法国人

84

当在与父对象具有相同原点的iframe中时,该window.frameElement方法返回嵌入窗口的元素(例如iframeobject)。否则,如果在顶级上下文中浏览,或者父级和子级框架的起源不同,则它将求值为null

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

这是HTML标准,所有现代浏览器都提供基本支持。


2
请注意frameElement,根据W3C的说法,尝试读取将在跨域iframe中抛出SecurityError异常(WHATWG表示应返回null)。因此,您可能希望将其包装在try...catch语句中。
Oriol

5
进入null内部和外部iframe
OlehZiniak

4
MDN上的描述说:“如果嵌入文档的文档具有不同的来源(例如,来自不同的域),则为null。”
xeophin

只是为了弄清楚回报应该是什么:Returns the element (such as <iframe> or <object>) in which the window is embedded, or null if the element is either top-level or is embedded into a document with a different script origin; that is, in cross-origin situations.
Art3mix

26

RoBorg是正确的,但我想补充一点。

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

到目前为止,一切都很好。现在出现了错误。

可以说,与其像普通的那样单击原始链接,然后在“ baz”框架中加载special.html页面,不如单击鼠标中键或选择在新的选项卡中打开它。

当新标签页加载时(根本没有父框架!),IE将进入无休止的页面加载循环!因为IE“复制”了JavaScript中的框架结构,因此新标签页确实有一个父级,而该父级的名称是“ bar”。

好消息是检查:

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

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


该错误已得到修复吗?我无法在IE8中重现它。我总是正确的window.parent
user123444555621 2012年

1
不确定-我将针对IE9及以下版本再次运行我的测试套件,然后发布更新。
scunliffe 2012年

18

在Firefox 6.0扩展程序(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中运行。


1
尝试document.defaultView.self === document.defaultView.topwindow !== window.top。在Firefox附加SDK的内容脚本中,全局self对象是用于与主脚本进行通信的对象。
罗伯W

13

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

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

6
还是简单地!(window===window.parent)
CalculatorFeline

11
window!== window.parent
伊万·列昂

5

我正在使用这个:

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

为什么这样做:.indexOf("HTMLIFrameElement")
路加福音

.indexOf('foobarbaz')> -1是一种检查“子字符串匹配”的方法(即,可以在字符串中的某个位置找到“ foobarbaz”吗?),但无需使用正则表达式。从逻辑上讲,它等效于.match(/ foobarbaz /)。它(用于:-)可在更广泛的浏览器上运行,但出于习惯或由于担心正则表达式机制的性能而仍可能使用。
Chuck Kollars,2013年

2

使用此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

至今最佳的旧版浏览器框架中断脚本

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

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

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

<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仅需要一个方法/标记库。

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


1
框架是不是唯一的威胁,反对左右(使用HTML5对象标记它取代iframe标签的意思)......我想针对..这是行不通的
雷蒙德Nijland

2
if ( window.location !== window.parent.location ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}

1

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

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


1

我实际上曾经检查过window.parent并为我工作,但是最近window是一个循环对象,并且始终具有父键,iframe或没有iframe。

正如评论所建议的那样,很难与window.parent进行比较。如果iframe与父网页完全相同,则不确定是否可以使用。

window === window.parent;

在铬在主窗口上下文window.parent === window是正确的。所以你的答案是不正确的。而且这种比较可以用于检查(至少在chrome中,没有在其他浏览器中对其进行测试)。
MarkosyanArtur'2

在iFrame的环境中不起作用,但是`if(window === window.parent){`可以。我不会拒绝您,因为我不知道为什么它不起作用
www-0av-Com

-1

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

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

要添加到Eneko Alonso:这有效(parent.location == self.location)
piotr_cz

@piotr_cz,仅在同源策略允许访问时才有效parent.location。否则会引发异常
2014年

-1

如果您想知道用户是否正在从Facebook页面选项卡或画布访问您的应用程序,请检查“签名请求”。如果您不了解,则可能是用户未从Facebook访问。为了确保确认signed_request字段结构和字段内容。

使用php-sdk,您可以像这样获得Signed Request:

$signed_request = $facebook->getSignedRequest();

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

https://developers.facebook.com/docs/reference/php/facebook-getSignedRequest/

和这里:

https://developers.facebook.com/docs/reference/login/signed-request/


-1

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

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

-4
if (window.frames.length != parent.frames.length) { page loaded in iframe }

但是,只有在您的网页和将您加载到iframe中的网页的iframe数量不同时,才可以。在您的网页中没有iframe可以保证此代码的结果100%


确定窗口是否在iframe内不是一个非常优雅的解决方案,也不保证您也可以从parent.frames中读取内容。
珀西

-4

在每个页面中编写此JavaScript

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

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


4
不在框架中时,重定向将起作用。因此,我将无法在您的站点中导航。其次,存在防止从父页面重定向的技术。
MariusBalčytis13年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.