[FE] 怎样利用window.name拿到跨域数据

96
何幻
2017.03.06 20:04* 字数 618

1. window.name的性质

window.name有一个奇妙的性质,
页面如果设置了window.name,那么在不关闭页面的情况下,
即使进行了页面跳转location.href=...,这个window.name还是会保留。

我们可以在控制台做一下实验:

// 打开必应 https://www.bing.com/
// 保留控制台log(勾上Preserve log

> window.name
""

> window.name='test';
"test"

> location.href='http://www.google.com';
"http://www.google.com"
Navigated to https://www.google.com/

> window.name
"test"

利用这一点,我们就可以拿到其他域中的数据了。


2. 跨域请求

我们知道,使用iframesrc属性,可以加载不同域中的网页,
我们也可以使用$('iframe').contentWindow来拿到iframe中页面的window对象,
只是这个window对象中可以访问的属性是很少的。

> Object.keys($('iframe').contentWindow);
["postMessage", "blur", "focus", "close", "parent", "opener", "top", "length", "frames", "closed", "location", "self", "window"]

访问其他属性,会报错:

Uncaught DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.

而如果使用iframe加载同域的页面,访问$('iframe').contentWindow的属性是不会报错的,它就是iframe内页面的完整的window对象。

3. 整合

利用window.name的性质,我们可以在iframe中加载一个跨域页面。

这个页面载入之后,让它设置自己的window.name
然后再让它进行当前页面的跳转,跳转到与iframe外的页面同域的页面
此时window.name是不会改变的。

这样,iframe内外就属于同一个域了,且window.name还是跨域的页面所设置的值。

假设我们有3个页面,
a.com/index.html
a.com/empty.html
b.com/index.html

(1)在a.com/index.html页面中嵌入一个iframe,设置srcb.com/index.html
(2)b.com/index.html载入后,设置window.name,然后再使用location.href='a.com/empty.html'跳转到与iframe外页面同域的页面中。
(3)在a.com/index.html页面中,就可以通过$('iframe').contentWindow.name来获取iframe内页面a.com/empty.htmlwindow.name值了,而这个值正是b.com/index.html设置的。

注意:
(1)让iframe内的跨域页面,在设置了window.name之后,跳转到与iframe外页面同域的页面,这个过程是必须,否则通过$('iframe').contentWindow.name访问会报跨域错误。
(2)实际操作中,我们一般使用一个隐藏的iframe,然后监听它第二次onload事件,就知道该iframe已经跳到同域页面了,然后使用$('iframe').contentWindow.name即可。


参考

利用window.name+iframe跨域获取数据详解
Cross domain using window.name — double onload should be used?

2017.03