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. 跨域请求
我们知道,使用iframe
的src
属性,可以加载不同域中的网页,
我们也可以使用$('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
,设置src
为b.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.html
的window.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?