ChatGPT解决这个技术问题 Extra ChatGPT

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

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

一些不错的方法(包括评论):tommcfarlin.com/check-if-a-page-is-in-an-iframe
外部链接不是回答问题的好方法。特别是如果这些外部链接的内容可以减少到 return window.location !== window.parent.location

J
James Gentes

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

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

topself 都是 window 对象(连同 parent),因此您可以查看您的窗口是否是顶部窗口。


这似乎在 Firefox 中运行良好。它也适用于其他浏览器吗?
在 iframe 中有一个带有 iframe 的页面,从我的子 iframe 测试我的父 iframe 是否嵌入在页面中,我使用了 if (parent === top)
@sglessard 如果子页面和父页面来自不同的域,那么 Firefox 将抱怨同源策略(www.w3.org/Security/wiki/Same_Origin_Policy)并且代码将不起作用
这对我来说适用于 IE 11、10 和 9。它也适用于 FF 和 Opera,当然还有 Chrome。我没有遇到任何问题。
对于那些仍在使用 1995 年最新技术的人,当从 frame iframe 的内容中运行时,window.self !== window.top 返回 true
C
CertainPerformance

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

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

这是一个在所有现代浏览器中都具有基本支持的 HTML Standard


请注意,根据 W3CWHATWG 表示它应该返回 null),尝试读取 frameElement 将在跨域 iframe 中引发 SecurityError 异常。因此,您可能希望将其包装在 try...catch 语句中。
nulliframe 内外
MDN 处的描述说“如果嵌入它的文档具有不同的来源(例如来自不同的域),则为空。”
只是为了澄清回报应该是什么: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.
像一个魅力一样工作,包括在同域嵌套 iframe 上。非常感谢!
s
scunliffe

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

在 IE7/IE8 中,当微软在他们的浏览器中添加选项卡时,他们破坏了一件事情,如果你不小心的话,这会对你的 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”,它会在 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
不确定 - 我将再次针对 IE9 及以下版本运行我的测试套件并发布更新。
现在是 2021 年,我还在 IE 的坟墓上跳舞。
可悲的是,我仍然支持 IE……尽管我肯定会庆祝我不再需要的那一天。 ;-)
p
portal TheAnGeLs

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

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

或者干脆!(window===window.parent)
窗口!== window.parent
iFrameDetection 在弹出窗口的情况下返回误报。所以要正确检测 iframe,它应该是 var iFrameDetection = (window === window.parent || window.opener) ? false : true;
@CalculatorFeline 我更喜欢作者写的明确声明,因为乍一看它可以更快地理解,因此代码的错误更少。 Minificator 工具为我完成了这项工作,以便在部署时以最短的方式重写它。为什么我应该编写对人类来说可读性更差的缩小代码?
Ivan 建议使用 !== 怎么样?
P
PowerKiKi
if ( window !== window.parent ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}

除非您打开自己网站的 iframe。
m
magnoz

在 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 中确定它是否在其中一个 iframe 中运行。


试试 document.defaultView.self === document.defaultView.topwindow !== window.top。在 Firefox 的附加 SDK 的内容脚本中,全局 self 对象是用于与主脚本通信的对象。
C
Chuck Norris

我正在使用这个:

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

你为什么这样做:.indexOf("HTMLIFrameElement")
.indexOf('foobarbaz') > -1 是一种检查“子字符串匹配”的方法(即可以在字符串中的某处找到“foobarbaz”吗?),但不使用正则表达式。它在逻辑上等同于 .match(/foobarbaz/)。它(用于:-)适用于更广泛的浏览器,并且仍然可能出于习惯或担心正则表达式机制的性能而使用。
R
Rolf

使用这个 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;
}

C
Community

目前最好的旧版浏览器断帧脚本

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

防御点击劫持的一种方法是在每个不应加框的页面中包含一个“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


框架不是唯一的威胁,反对呢(意思是使用 HTML5 对象标签替换 iframe 标签).. 我认为这对它不起作用..
J
Jabran Saeed

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

正如评论所暗示的那样,很难与 window.parent 作品进行比较。如果 iframe 与父网页完全相同,则不确定这是否可行。

window === window.parent;

在主窗口上下文 window.parent === window 中的 chrome 中为 true。所以你的答案是不正确的。并且这种比较可以用于检查(至少在 chrome 中,没有在其他浏览器中测试它)。
在 iFrame 的上下文中不起作用,但 ` if(window === window.parent){ ` 可以。我没有标记你,因为我不知道为什么它不起作用
H
HectorMac

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

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


K
Karthikeyan
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;
    }
}

J
James

按照 @magnoz 的说法,这是他的答案的代码实现。

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!')
    }
}

E
Error601

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

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,它仅在同源策略允许访问 parent.location 时才有效。否则抛出异常
J
Joao Belchior

如果您想知道用户是否从 facebook 页面选项卡或画布访问您的应用程序,请检查签名请求。如果你不明白,可能用户没有从 facebook 访问。确保确认 signed_request 字段结构和字段内容。

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

$signed_request = $facebook->getSignedRequest();

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

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

和这里:

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


A
Alex Roseland

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

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

V
Vova Popov
if (window.frames.length != parent.frames.length) { page loaded in iframe }

但前提是您的页面和在 iframe 中加载您的页面中的 iframe 数量不同。在您的页面中不设置 iframe 以 100% 保证此代码的结果


确定窗口是否在 iframe 内不是一个非常优雅的解决方案,也不能保证您也可以从 parent.frames 读取。
@Percy 为什么不呢? window.frames 是否允许跨源属性?
A
Alexis Wilke

在每个页面中编写此 javascript

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

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


当您不在框架时,您的重定向将起作用。所以我将无法在您的网站中导航。其次,存在防止从父页面重定向的技术。