假设页面http://www.example.com/a.html和http://www.example.com/b.html属于不同域,a页面请求b页面的内容.
document.domain
利用document.domain实现跨域的前提是这两个域名必须属于同一个基础域名,协议端口都要一致。主要是父域和子域之间的通信
-
如aaa.com下的网页a.html通过iframe引用bbb.com下的网页b.html,这时a.html里面能看到b.html的内容,但不能用JS操作它,因为属于不同域。
-
另一种情况:两个子域名aaa.xxx.com和bbb.xxx.com,aaa.xxx.com下的网页a.html通过iframe引用bbb.xxx.com下的网页b.html,仍不能操作因为域名不同,此时可将这两个页面的domain改为一样的
document.domain="xxx.com"
这就实现了同一基础域名之间的跨域。 - 将b页面通过iframe引入a页面,也可将其隐藏,在两个页面中的script 中将document.domain设置成两页面公共的父级域名
example.com
,如果两页面都是本地载入的,可用localhost。按以下引用b页面:
var iframe = document.getElementById("iframe");
var bDocument = iframe.contentDocument;
此时bDocument
即是b页面的document
对象,可引用b页面的内容;
window.name
- 从一个窗口下打开的另一个页面和父窗口拥有相同的window.name值
- window.name是当前窗口的名字,每个iframe都有包裹他的window,这个window 也有他自己的window.name,
- window.name的值在不同页面加载后依然存在,未修改值不变(2MB)。
-
假设index.html要请求服务器上的数据:在index.html页面下:
iframe=document.getElementById("iframe"); iframe.src='http://localhost:8080/data.php'; iframe.onload=function(){console.log(iframe.contentWindow.name)}
然而由于要求协议主机端口必须一致才能请求,因此此时已经跨域了,由于window.name的值保持不变,可在index.html页面相同目录中新建proxy.html:
- 1
- 2
- 3
- 4
此时虽然能正确得到
window.name
的值,但是由于每次iframe.src
的加载都执行iframe.onload
,循环执行,页面循环刷新,解决办法:- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
将要从b页面获取的值设置成b的
window.name
,然后从b页面载入a页面window.locattion='http://www.example.com/a.html'
,同样获取window.name
,即是b页面设置的值。
原理:iframe的跨域能力及window.name在页面刷新后依旧存在。
H5的window.postMessage(实时通信)
postMessage(data,origin)
data
表示要传递的数据,部分浏览器只能处理字符串参数,可用JSON.stringify
将对象序列化。
origion
:目标窗口的源,协议主机端口号,也可设为*,即传递给任意窗口。
http://test.com/index.html,在index.html中,主页面向iframe发送请求:
window.onload=function(){
window.frames[0].postMessage('getcolor','http://lslib.com')
}
//主页面接受iframe传来的消息
window.addEventListener('message',function(e){
console.log(e.data);
})
lsLib.html:
//iframe接受消息,向主页面反馈信息:
window.addEventListener('message',function(e){
if(e.source!=widow.parent) return;
window.parent.postMessage('someinfor come from iframe','*')
},false);
jsonp(从服务器获取数据,兼容性好)
要获取不同域上的json对象,假设http://www.example.com/data.php为a.html页面不同域上的json对象。要在a中引用data.php里面返回的数据可在a中这样写:
function dosomething(data){
//处理获取到的data
}
也可以用jQuery封装好的函数:
$.getJSON("http://www.example.com/data.php?callback=?",function(data){
//处理获取到的data
})
针对JSONP的另一个例子
function handleResponse(response){
console.log(response.ip,response.city);}
var script = document.createElement('script');
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.head.a(script);
输出:210.74.131.196 ,因为http://freegeoip.net/json/的页面内容是:
{"ip":"210.74.131.196","country_code":"CN","country_name":"China","region_code":"","region_name":"","city":"","zip_code":"","time_zone":"","latitude":34.7725,"longitude":113.7266,"metro_code":0}
然而jsonp
跨域可能造成XSS
攻击,因此客户端接收callback参数时,若其中包含恶意标签(script
)则可能存在风险,解决办法在服务器端用encodeURI
对callback参数进行编码,客户端再用decodeURIComponent
解码。
JSONP缺点分析
- 只支持GET请求,不支持其他http method方法
- 返回出错的话也不会提示错误的状态码
- 只支持跨域HTTP请求,不支持两个页面的JavaScript互相调用问题
- 存在注入攻击,则调用这个资源的页面都会受到影响
图像Ping
与服务器进行简单单向通信,一个网页可以加载任意网页上的图片
CORS(cross origin resource share)
定义一种跨域资源访问机制,基本思想是服务器发送一个HTTP响应表头
假设www.a.com
要从www.b.com
上请求数据。因为跨域所以响应失败,可在www.b.com
中添加
header('Access-Control-Allow-Origin:www.a.com')
则可接受www.a.com
的请求,header('Access-Control-Allow-Origin:*')
表示接受所有请求
总结
- iframe缺点:阻止主页面的Onload事件,搜索引擎程序无法解读这种页面,不利于SEO(search engine optimization),会影响页面的并行加载(同一时间针对同一域名下的请求,各浏览器不同)。
- 解决方法,可在js中动态设置其src属性。