Як визначити, чи завантажується веб-сторінка всередині iframe або безпосередньо у вікно браузера?


596

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


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

Відповіді:


1106

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

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

topі selfобидва windowоб'єкти (разом з ними parent), тож ви бачите, чи це ваше вікно верхнє вікно.


4
Схоже, це добре працює у Firefox. Чи працює це і в інших браузерах?
акшат

5
Маючи сторінку з рамкою iframe в рамках iframe, щоб перевірити, чи є моя дитина iframe, чи мій батьківський iframe був вбудований у сторінку, я використовував if (parent === top)
sglessard

7
@sglessard Якщо дочірня сторінка та батьків є з різних доменів, Firefox подасть скаргу на політику щодо того
самого оригіналу

18
Це працює в IE 11, 10 і 9 для мене. Також він працює у FF і Opera, а також, звичайно, в Chrome. Я не стикався з цим жодних проблем.
jeremysawesome

4
Для тих , хто все ще похитуючись останньої в 1995 році технології, window.self !== window.topповертається trueпри запуску всередині вмісту frame, або iframe .
Jeromy French

84

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

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

Це стандарт HTML із базовою підтримкою у всіх сучасних браузерах.


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

5
потрапляння nullвсередину та ззовніiframe
OlehZiniak

4
В описі 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.
віддача

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, щоб перевірити, чи є в "батьківщині" кадр під назвою "bar", він повернеться істинним (очікуваним).

Тепер скажемо, що сторінка special.html, коли вона завантажується, перевіряє батьківський кадр (на наявність та його ім'я, а якщо він є "бар", він перезавантажується в рамку бар. Наприклад

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

у цій новій вкладці повертається істина, і, таким чином, ви можете перевірити наявність цього дивного стану.


Чи помилка виправлена ​​тим часом? Я не можу відтворити його в IE8. Я завжди отримую правильне window.parent.
користувач123444555621

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

18

Прийнята відповідь не працювала для мене всередині скрипту вмісту розширення Firefox 6.0 (Addon-SDK 1.0): Firefox виконує скрипт вмісту в кожному: вікні верхнього рівня та у всіх кадрах.

Всередині скрипту вмісту я отримую такі результати:

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

Дивна річ у цьому виході - це те, що він завжди однаковий, незалежно від того, чи запускається код всередині рамки кадрів чи вікна верхнього рівня.

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

Що нарешті для мене спрацювало у контентному скрипті в обох браузерах:

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

Без рамок цього друкується 0:0у вікні верхнього рівня, що містить один кадр, і друкується 1:1в єдиній рамці документа 0:1.

Це дозволяє моєму розширенню визначати в обох браузерах, чи є якісь iframe, а також у Firefox, якщо він запускається всередині одного з кадрів.


1
Спробуйте document.defaultView.self === document.defaultView.topабо window !== window.top. У вмістовому скрипті SDK для додатка Firefox глобальний selfоб’єкт - це об'єкт, який використовується для зв'язку з основним сценарієм.
Роб Ш

13

Я не впевнений, як цей приклад працює для старих веб-браузерів, але я використовую це для IE, Firefox та Chrome без випуску:

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 /). Він (використовується для :-) роботи в більш широкому діапазоні браузерів, і все ще може використовуватися або за звичкою, або через побоювання щодо функціонування механізму регулярного вираження.
Чак Колларз

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

Сценарій найкращого на сьогодні застарілого кадру браузера

Інші рішення для мене не спрацювали. Цей працює у всіх браузерах:

Один із способів захисту від клік-джеккінгу - це включення сценарію "вимикач кадрів" на кожну сторінку, яка не повинна бути обрамлена. Наведена нижче методологія запобігає формуванню веб-сторінки навіть у застарілих браузерах, які не підтримують заголовки X-Frame-Options.

До елемента 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
обрамлення не є єдиною загрозою, що стосується заперечень (мається на увазі використання тега об’єкта HTML5, який замінює тег iframe). Я думаю, що проти цього не вийде ..
Реймонд Ніджленд

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

1

Оскільки ви запитуєте в контексті програми facebook, ви можете розглянути можливість виявлення цього на сервері, коли буде зроблено початковий запит. Facebook передасть купу даних запитів, включаючи ключ fb_sig_user, якщо він викликається з iframe.

Оскільки вам, ймовірно, потрібно перевірити та використовувати ці дані у будь-якому випадку у вашій програмі, скористайтеся ними для визначення відповідного контексту для відображення.


1

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

Як зазначають коментарі, важко порівнювати з роботами window.parent. Не впевнений, чи це спрацює, якщо iframe точно та сама веб-сторінка, що і батьківська.

window === window.parent;

у хромі в контексті головного вікна window.parent === windowвірно. Тож ваша відповідь неправильна. І це порівняння можна було б використати для перевірки (принаймні в хромі, не тестувало його в інших браузерах).
MarkosyanArtur

НЕ ПРАЦЮЄ в контексті iFrame, але "якщо (вікно === window.parent) {` робить. Я не відзначаю вас, бо не знаю, чому це не працює
www-0av-Com

-1

Це давній код, який я кілька разів використовував:

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

Додати до Енеко Алонсо: це працює(parent.location == self.location)
piotr_cz

@piotr_cz, вона працює лише в тому випадку, якщо політика одного походження дозволяє отримати доступ до parent.location. Інакше викинуто виняток
Дан

-1

Якщо ви хочете знати, чи користувач отримує доступ до вашої програми із вкладки на сторінці у facebook чи на полотні, перевірте наявність підписаного запиту. Якщо ви цього не отримаєте, ймовірно, користувач не має доступу до facebook. Щоб переконатися в підтвердженні структури підписаних_запитів і вмісту полів.

За допомогою php-sdk ви можете отримати такий підписаний запит:

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

Але лише в тому випадку, якщо кількість ваших кадрів iframes відрізняється на вашій сторінці та сторінці, які завантажують вас у iframe. Не робіть жодної iframe на своїй сторінці, щоб мати 100% гарантію на результат цього коду


Не дуже елегантне рішення для визначення того, чи знаходиться вікно всередині iframe чи ні, і немає гарантії, що ви зможете прочитати і з parent.frames.
Персі

-4

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

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

Тоді воно автоматично переспрямовується на головну сторінку.


4
Перенаправлення буде працювати, коли ви не є кадром. Тож я б не зміг орієнтуватися на вашому сайті. По-друге, існують методи, що запобігають перенаправленню з батьківської сторінки.
Маріус Бальчітіс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.