Я приобрел больше опыта в результате экспериментов, поэтому вот что я узнал до сих пор.
Как я и думал, мы можем разрешить реферера через document.referrer
(браузер) и req.headers.referer
(сервер).
Таким образом, можно определить, отличается ли текущий реферер от нашего хост-сервера, и в этом случае мы знаем, что запрос поступил из iframe.
С серверной стороны становится сложнее узнать, была ли страница вашего сайта загружена через iframe на этом же сайте. В таком случае невозможно автоматически определить, запускаем ли мы страницу из iframe или нет.
Например, если у вас есть iframe на странице /index
, который загружает /page2
page, то вы не можете узнать, со стороны сервера, был ли / page2 загружен из iframe (on / index) или из перехода на /page2.
И именно поэтому люди говорят, что есть со стороны сервера невозможно узнать, была ли страница загружена через iframe. Потому что это неясно.
Теперь моя реальная потребность была немного другой. Мне нужно было знать, был ли мой /page2
загружен из другого домена, который принадлежит мне (кросс-домен), и это довольно просто узнать, поскольку реферер будет отличаться от моего собственного домена, как на стороне сервера, так и на стороне браузера.
С моими интеграционными тестами стало немного сложнее, потому что у меня была страница /tests/iframeIntegration
, которая содержит iframe, который загружает другую страницу /page2
из того же домена. (относительный URL)
Цель состояла в том, чтобы проверить, работала ли интеграция iframe должным образом, и поскольку она работала в том же домене, я не мог определить, загружал ли я ее через iframe.
Для этого конкретного случая я добавил /page2?iframe=true
в URL. Это самый простой обходной путь, который я нашел, который работает универсально (браузер + сервер).
Вот несколько служебных скриптов:
import { isBrowser } from '@unly/utils';
import includes from 'lodash.includes';
/**
* Resolves whether the current web page is running as an iframe from another page
*
* Iframes are only detectable on the client-side
* Also, using iframe=true as search parameter forces iframe mode, it's handy when using an iframe from the same domain
* (because same-domain iframes aren't detected when comparing window.parent and window.top since it's the same window)
*
* @return {boolean}
* @see https://stackoverflow.com/a/326076/2391795
*/
export const isRunningInIframe = (): boolean => {
if (isBrowser()) {
try {
return window.self !== window.top || includes(document.location.search, 'iframe=true');
} catch (e) {
return null; // Can't tell
}
} else {
return null; // Can't tell
}
};
/**
* Resolve the iframe's referrer (the url of the website the iframe was created)
*
* Helpful to know which of our customer use our app through an iframe, and analyse usage
* May not always work due to security concerns
*
* @return {string}
* @see https://stackoverflow.com/a/19438406/2391795
*/
export const getIframeReferrer = (): string => {
if (isRunningInIframe()) {
try {
return document.referrer || null;
} catch (e) {
return null;
}
} else {
return null;
}
};