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

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

Ответы [ 15 ]

975 голосов
/ 28 ноября 2008

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

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

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

78 голосов
/ 08 сентября 2013

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

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

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

25 голосов
/ 28 ноября 2008

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

В 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, и, таким образом, вы можете проверить это странное условие.

18 голосов
/ 14 октября 2011

Принятый ответ не работал для меня в скрипте содержимого расширения Firefox 6.0 (Addon-SDK 1.0): Firefox выполняет скрипт контента в каждом: окне верхнего уровня и во всех фреймах.

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

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

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

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

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

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

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

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

7 голосов
/ 19 ноября 2015

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

var iFrameDetection = (window === window.parent) ? false : true;
5 голосов
/ 20 июня 2012

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

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
2 голосов
/ 21 сентября 2011

Используйте эту функцию 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;
}
1 голос
/ 12 апреля 2018

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

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

Один из способов защиты от кликджекинга состоит в том, чтобы включить в каждую страницу сценарий «разрыва фрейма», который не должен быть оформлен. Следующая методология предотвратит создание веб-страницы даже в устаревших браузерах, которые не поддерживают 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

1 голос
/ 04 марта 2014

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

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

window === window.parent;
1 голос
/ 12 декабря 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...