详解
前文提到用jsonp的方式来跨域获取数据,本文为大家介绍下如何利用window.name+iframe跨域获取数据。
首先我们要简单了解下window.name和iframe的相关知识。iframe是html的一个标签,可以在网页中创建内联框架,有个src属性(指向文件地址,html、php等)可以选择内联框架的内容。window.name(一般在js代码里出现)的值不是一个普通的全局变量,而是当前窗口的名字,这里要注意的是每个iframe都有包裹它的window,而这个window是top window的子窗口,而它自然也有window.name的属性,window.name属性的神奇之处在于name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。
跨域解决方案似乎可以呼之欲出了,假设index.html页面请求远端服务器的数据,我们在该页面下新建一个iframe标签,该iframe的src属性指向服务器文件地址(利用iframe标签的跨域能力),服务器文件里设置好window.name的值(也就是该iframe的contentWindow的name值),然后在index.html里读取该iframe的window.name值,一切似乎水到渠成,代码如下:
|
|
但是不幸的是,报错了..
提示啥协议、主机、端口三者要一致,这不是赤裸裸地告诉你跨域了么!为什么会这样,因为规定如果index.html页面和和该页面里的iframe框架的src如果不同源,则也无法操作框架里的任何东西,所以就取不到iframe框架的name值了,告诉你我们不是一家的,你也休想得到我这里的数据。既然要同源,那就换个src去指,前面说了无论怎样加载window.name值都不会变化.
域a.com的页面request.html(即http://a.com/request.html) 里面嵌套了一个iframe指向域b.com的response.html,而response.html里又嵌套了域a.com的proxy.html。
于是我们在index.html相同目录下,新建了个proxy.html的空页面,修改代码如下:
|
|
总结
能使用这种方式跨域,有几个条件必不可少。
- iframe标签的跨域能力
- window.name属性值在文档刷新后依旧存在的能力
再简单了解下window和contentWindow的一些知识。浏览器就会为原始文档创建一个 window 对象,再为每个框架(iframe)创建额外的 window 对象。这些额外的对象是原始窗口的子窗口,可能被原始窗口中发生的事件所影响。例如,关闭原始窗口将导致关闭全部子窗口。contentWindow属性是指指定的frame或者iframe所在的window对象。
使用方法
很多人或许只关注使用方法,而对原理不怎么感冒。此法相对于jsonp复杂,使用方法也更复杂些。
服务端一般输出一段js代码,例如下面这样:
|
|
window.name的值是字符串形式,也是需要传递给客户端的数据(当然如果有需要服务端也可以先处理传过来的数据,这里仅为只有数据回传),有需要自己再去解析(如字符串->json数据)。
index.html页面,我把方法封装成了函数:
|
|