Как определить, загружается ли веб-страница внутри iframe или непосредственно в окно браузера?

Я пишу приложение facebook на основе iframe. Теперь я хочу использовать одну и ту же страницу html для отображения обычного веб-сайта, а также страницы холста в facebook. Я хочу знать, могу ли я определить, была ли страница загружена внутри iframe или непосредственно в браузере?

Несколько хороших способов (включая комментарии): tommcfarlin.com/check-if-a-page-is-in-an-iframe

simhumileco 20.01.2019 11:03
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
648
1
347 957
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

Ответ принят как подходящий

Браузеры могут блокировать доступ к window.top из-за та же политика происхождения. Ошибки IE также имеют место. Вот рабочий код:

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

top и self являются объектами window (вместе с parent), поэтому вы видите, является ли ваше окно верхним окном.

Кажется, это нормально работает в Firefox. Это работает и в других браузерах?

akshat 28.11.2008 18:51

Имея страницу с iframe внутри iframe, чтобы проверить из моего дочернего iframe, был ли мой родительский iframe встроен в страницу, я использовал if (parent === top)

sglessard 27.03.2012 18:31

@sglessard Если дочерняя страница и родительская страница из разных доменов, Firefox будет жаловаться на одну и ту же политику происхождения (www.w3.org/Security/wiki/Same_Origin_Policy), и код не будет работать

Gaurang Jadia 01.08.2012 02:10

это НЕ говорит вам, что родитель обязательно facebook, хотя

dsdsdsdsd 21.01.2013 13:29

У меня это работает в IE 11, 10 и 9. Также он работает в FF и Opera и, конечно же, в Chrome. У меня не было никаких проблем с этим.

jeremysawesome 22.08.2013 20:40

Достаточно просто, спасибо :). Хотя мне это нужно для критически важной части моего проекта. Может это удержать ?? Я имею в виду, можно ли это обмануть?

Milad.Nozari 21.09.2013 10:17

@MNVOH, проверьте это в IE8

Dan 13.01.2014 13:57

@MNVOH Обновил решение, проверьте его.

Dan 13.01.2014 14:35

Последнее обновление вызывает у меня ошибку. Не улавливает ли параметр?

Mike 16.01.2014 22:44

Да, я почти уверен, что catch требует параметра ... У меня тоже не работает как есть.

rinogo 21.01.2014 01:04

Это не удастся, если происхождение совпадет. Window.top будет доступен для iframe.

Jabran Saeed 04.03.2014 07:50

Я думал, что это не работает в IE11 (Windows 7), пока не Я включил консоль разработчика; тогда это сработало. Оказывается, в моем коде был «console.info», чтобы показать мне, что происходило в логике, и похоже, что IE11 выдает ошибку, если вы вызываете console.info, а консоль не подключена. Без регистрации у меня это работает в Chrome, Firefox, IE11 и Safari (Windows 7 и OSX, где это необходимо).

Andrew Richard Miller 08.02.2016 13:09

Для тех, кто все еще использует новейшие технологии 1995 года, window.self !== window.top возвращает true при запуске из содержимого frame, или жеiframe.

Jeromy French 23.03.2017 23:13

«Браузеры могут блокировать доступ к window.top из-за той же политики происхождения». Ты уверен? Он может блокировать доступ к свойствам на window.top, но я понимаю, что он не будет блокировать доступ к самому window.top. Страница, на которую вы указали ссылку, похоже, поддерживает это (см. Доступ к API-интерфейсу скриптов из разных источников).

Aaronius 25.10.2017 06:48

@JoshHabdas - Я хотел бы понять, почему это лучший подход?

phillyslick 11.12.2018 21:56

Одним словом @phillyslick: выразительность.

Josh Habdas 21.12.2018 05:07

Как это замечательно и полезно!

Khateeb321 14.01.2019 18:36

@JoshHabdas frameElement будет давать ложные срабатывания, если страница встроена в страницу из другого источника: "возвращает ... null, если элемент либо находится на верхнем уровне, либо встроен в документ с другим источником скрипта; то есть перекрестно -начальные ситуации ". developer.mozilla.org/en-US/docs/Web/API/Window/frameElement

Skitterm 20.06.2019 22:55

@Skitterm, спасибо. теперь я понимаю, почему этот подход лучше.

Josh Habdas 22.06.2019 16:19

Роборг прав, но я хотел добавить примечание.

В IE7 / IE8, когда Microsoft добавила вкладки в свой браузер, они сломали одну вещь, которая нанесет ущерб вашему 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;
}

Все идет нормально. Теперь идет ошибка.

Допустим, вместо того, чтобы щелкнуть исходную ссылку, как обычно, и загрузить страницу special.html во фрейме «baz», вы щелкнули по ней средней кнопкой мыши или решили открыть ее в новой вкладке.

Когда эта новая вкладка загружается (без родительских фреймов!) IE войдет в бесконечный цикл загрузки страницы!, потому что IE «копирует» структуру фрейма в JavaScript, так что новая вкладка ДЕЙСТВИТЕЛЬНО имеет родителя, а у этого родителя ИМЕЕТ имя «bar».

Хорошая новость в том, что проверка:

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

в этой новой вкладке возвращает true, и поэтому вы можете проверить это странное условие.

Исправлена ​​ли ошибка тем временем? Я не могу воспроизвести это в IE8. Я всегда получаю правильный window.parent.

user123444555621 10.09.2012 11:22

Не уверен - я снова запущу свой набор тестов для IE9 и ниже и опубликую обновление.

scunliffe 11.09.2012 00:36

Это 2021 год, а я все еще танцую на могиле IE.

Michael Scheper 24.03.2021 15:14

К сожалению, я все еще поддерживаю IE ... хотя я определенно буду отмечать день, когда мне больше не нужно. ;-)

scunliffe 24.03.2021 23:09

Поскольку вы запрашиваете в контексте приложения facebook, вы можете рассмотреть возможность обнаружения этого на сервере при выполнении первоначального запроса. Facebook передает кучу данных строки запроса, включая ключ fb_sig_user, если он вызывается из iframe.

Поскольку вам, вероятно, все равно придется проверять и использовать эти данные в своем приложении, используйте их для определения соответствующего контекста для рендеринга.

Используйте эту функцию 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 выполняет сценарий содержимого в каждом: окне верхнего уровня и во всех окнах iframe.

Внутри скрипта содержимого я получаю следующие результаты:

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

Странность этого вывода заключается в том, что он всегда один и тот же, независимо от того, выполняется ли код внутри iframe или в окне верхнего уровня.

С другой стороны, Google Chrome, похоже, выполняет мой сценарий содержимого только один раз в окне верхнего уровня, поэтому вышеуказанное не будет работать вообще.

Что в итоге сработало для меня в сценарии содержимого в обоих браузерах:

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

Без iframe он печатает 0:0, в окне верхнего уровня, содержащем один фрейм, он печатает 1:1, а в единственном iframe документа он печатает 0:1.

Это позволяет моему расширению определять в обоих браузерах, есть ли какие-либо фреймы iframe, и дополнительно в Firefox, если оно запускается внутри одного из iframe.

Попробуйте document.defaultView.self === document.defaultView.top или window !== window.top. В сценарии содержимого SDK надстройки Firefox глобальный объект self - это объект, используемый для связи с основным сценарием.

Rob W 02.10.2013 01:39

Это древний фрагмент кода, который я использовал несколько раз:

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

Чтобы добавить Энеко Алонсо: это работает (parent.location == self.location)

piotr_cz 20.08.2013 16:21

@piotr_cz, он работает, только если политика одного и того же происхождения разрешает доступ к parent.location. В противном случае выдается исключение

Dan 13.01.2014 14:50

Я использую это:

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

Зачем вы это делаете: .indexOf("HTMLIFrameElement")?

Luke 14.08.2013 12:46

.indexOf ('foobarbaz')> -1 - это способ проверить "совпадение подстроки" (т.е. можно ли найти 'foobarbaz' где-нибудь в строке?), но без использования регулярных выражений. Логически эквивалентен .match (/ foobarbaz /). Он (раньше :-) работал с более широким спектром браузеров и все еще может использоваться либо по привычке, либо из-за опасений по поводу производительности механизма регулярных выражений.

Chuck Kollars 31.08.2013 04:01
if (window.frames.length != parent.frames.length) { page loaded in iframe }

Но только если количество фреймов отличается на вашей странице и странице, которая загружает вас в iframe. Не делайте iframe на своей странице, чтобы иметь 100% гарантию результата этого кода

Не очень элегантное решение для определения того, находится ли окно внутри iframe или нет, и нет никакой гарантии, что вы также сможете читать из parent.frames.

Percy 23.09.2015 01:27

Напишите этот javascript на каждой странице

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

Затем он автоматически перенаправляется на домашнюю страницу.

Ваше перенаправление будет работать, когда вы этого не сделаете, если frame. Поэтому я не смогу перемещаться по вашему сайту. Во-вторых, существуют методы предотвращения перенаправления с родительской страницы.

Marius Balčytis 14.05.2013 04:35

Если вы хотите узнать, обращается ли пользователь к вашему приложению с вкладки страницы 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/

Находясь в iframe из того же источника, что и родительский, метод window.frameElement возвращает элемент (например, iframe или object), в который встроено окно. В противном случае, при просмотре в контексте верхнего уровня или если родительский и дочерний фреймы имеют разное происхождение, он будет оцениваться как null.

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

Это Стандарт HTML с базовой поддержкой во всех современных браузерах.

Обратите внимание, что попытка чтения frameElement вызовет исключение SecurityError в iframe с перекрестным происхождением, согласно W3C (WHATWG говорит, что вместо этого он должен вернуть null). Так что вы можете заключить его в оператор try...catch.

Oriol 31.03.2016 17:20

получение null внутри и снаружи iframe

OlehZiniak 23.08.2017 13:22

В описании в MDN говорится, что «если документ, в который он встроен, имеет другое происхождение (например, находился в другом домене), он равен нулю».

xeophin 08.01.2018 13:40

Просто чтобы прояснить, какой должна быть отдача: 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 07.12.2018 20:12

Я на самом деле использовал для проверки window.parent, и это сработало для меня, но в последнее время окно является циклическим объектом и всегда имеет родительский ключ, iframe или без iframe.

Поскольку в комментариях предлагается жесткое сравнение с window.parent, работает. Не уверен, что это сработает, если iframe - это та же веб-страница, что и родительская.

window === window.parent;

в chrome в контексте главного окна window.parent === window верно. Значит, ваш ответ неверен. И это сравнение можно было использовать для проверки (по крайней мере, в хроме, в других браузерах не тестировал).

MarkosyanArtur 08.02.2017 14:29

НЕ РАБОТАЕТ в контексте iFrame, но `if (window === window.parent) {` работает. Я не отмечаю вас, потому что не знаю, почему это не работает

www-0av-Com 10.04.2018 16:24

Я не уверен, как этот пример работает для старых веб-браузеров, но я без проблем использую его для IE, Firefox и Chrome:

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

Или просто !(window===window.parent)

CalculatorFeline 12.04.2017 00:48

окно! == window.parent

Ivan Leonenko 05.06.2018 17:58

Самый лучший на данный момент скрипт разрыва фрейма в устаревшем браузере

Другие решения у меня не сработали. Этот работает во всех браузерах:

Один из способов защиты от кликджекинга - это включить на каждую страницу скрипт "взлома фреймов", который не должен быть во фрейме. Следующая методика предотвратит создание веб-страницы даже в устаревших браузерах, которые не поддерживают X-Frame-Options-Header.

В элементе HEAD документа добавьте следующее:

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

Сначала примените идентификатор к самому элементу стиля:

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

Таким образом, все может быть в документе HEAD, и вам понадобится только один метод / taglib в вашем API.

Ссылка: https://www.codemagi.com/blog/post/194

кадрирование - не единственная угроза, как насчет возражений (имеется в виду использование тега объекта HTML5, который заменяет тег iframe) .. я думаю, что это не сработает против этого ..

Raymond Nijland 28.12.2018 20:26

Это оказалось для меня самым простым решением.

    <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.location !== window.parent.location ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}

кроме случаев, когда вы открываете iframe своего собственного веб-сайта.

mkoryak 19.08.2020 05:49
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;
    }
}

Следуя тому, что сказал @magnoz, вот кодовая реализация его ответа.

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

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

Другие вопросы по теме