Skip to content
返回

如何得知我的网页是被哪个站点嵌入的?

现在有一个业务场景如下:

有三个站点,分别是 a.mydomain.com、b.mydomain.com 和 c.mydomain.com,其中 A 和 B 都会将 C 用 iframe 嵌入进来,现在有一个需求是当 C 被 A 嵌入的时候要执行一些逻辑。

从直觉上来看,C 只需要根据域名判断一下就好了:

if (top.location.href === 'a.mydomain.com') {
  // 站点 A
} else {
  // 站点 B
}

但在实际运行中,这样的做法会报错:

Blocked a frame with origin "c.mydomian.com" from accessing a cross-origin frame.

C 在尝试访问父页面时被浏览器阻止了,这里就引申出了浏览器的同源策略:两个页面的协议、域名和端口必须是一致的才可以相互访问对方的内容,但 C 和 A 的域名不相同,所以 C 在访问 A 的 URL 时被浏览器阻止了。

接下来怎么办?

第一种方法:document.referrer

document.referrer 可以获取到是哪个网址打开当前页面的,当 A 使用 iframe 嵌入了 C 时,C 的 referrer 就是 a.mydomain.com,但在使用时我们需要先判断自己是不是被 iframe 嵌入了:

if (top !== window) { // 先判断自己是不是在 iframe 里
  if (document.referrer === 'a.mydomain.com') {
    // 站点 A
  } else {
    // 站点 B
  }
}

这个方法的好处是无需修改其它站点的代码,但也有坏处:如果 A 嵌入了站点 D,然后 D 通过修改 location.href 的方式跳转到了 C,此时 C 的 referrer 就会是 D 而不是 A,这是不符合我们的预期的。

第二种方法:document.domain

document.domian 可以解决第一种方法中的问题。

在文章的开头,由于 A 和 C 的域名不同,所以 C 在读取 top.location.href 时报错了,但其实 A 和 C 都有一个相同的根域:mydomain.com,所以我们可以将 A 和 C 的 document.domain 都改为 mydomain.com,这样这两个站点的域就相同了。

我们首先需要在 A 中添加代码:document.domain = 'mydomain.com',然后在 C 中添加:

document.domain = 'mydomain.com'

// 我们只在 A 中设置了 document.domain,
// 如果父页面是 B 这里仍然会报错,
// 所以用了 try/catch
try {
  if (top.location.href === 'a.mydomain.com') {
    // 站点 A
  }
} catch(e) {
  // 站点 B
}

这样设置以后,C 不仅可以获取到 A 的 URL,同时还可以操作 A 中的 DOM,但它要求两个页面要有相同的根域,而第一种方法不需要。

总结

这两种方法各有利弊,在实际使用中可以根据业务场景酌情选择。


分享这篇文章:

上一篇
Framework7 Vue 踩坑记录
下一篇
MongoDB 中的索引和 Mongoose 中的 autoIndex