JS跨域解决方案详解 -演道网

本网站用的阿里云ECS,推荐大家用。自己搞个学习研究也不错

为什么需要跨域?

就得先知道同源策略.

同源策略

同源策略是为了保证数据的安全性,一个域的脚本不能去操作另外一个域的脚本的大多数的方法和属性.

相同域与不同域

相同域: 两个域具有相同的协议(http),相同的端口port,相同的host.

1
2
3
4
5
6
1 -》 http://www.csdn.net/blog/a.html
2 -》 http://www.csdn.net/b.html
3 -》 https://www.csdn.net/blog/c.html (协议不同)
4 -》 http://www.csdn.net:4040/blog/e.html(端口不同)
5 -》 http://csdn.net/blog/f.html (host不同)

1与2是同域,与其他都不是同域.

解决跨域的方法大致分为两种,一种是单向的数据请求,一种是双向的通信.

JSONP(单向跨域)

原理: 直接使用js的XMLHTTPRequest对象进行跨域是受到限制的,但是标签是不受到跨域的限制,这个标签是可以加载其他域的脚本.

场景需求: http://www.csdn.net/blog/a.html 想要获取http://csdn.net/blog/data.java提供的json数据.

  • 用原生js
1
2
3
4
5
6
7
8
9
10
//a,html
function( jsonData ){
//处理返回的json数据
}
/*
1.当data.java加载完成才会执行回调函数.http://csdn.net/blog/data.java返回的数据要是js的形式的
*/
  • 用jquery
1
2
3
4
5
$.getJson('http://csdn.net/blog/data.java?callback=?',function(data){
//处理返回的数据
});

flash URLLoader(单向跨域)

服务器可以通过crossdomain.xml文件来声明能被哪些域的SWF文件访问,SWF也可以通过API来确定自身能被哪些域的SWF加载

场景需求: www.csdn.cn 要请求www.node.cn的数据

1
在www.node.cn的crossdomain.xml文件(没有就自己创建)把www.csdn.cn加入白名单.通过Flash URLLoader发送HTTP请求,最后,通过Flash API把响应结果传递给JavaScript

document.domain来实现域与域,域与子域之间的通信(双向跨域)

不同域的框架之间不能进行js操作,但是可以获取彼此的window对象,不过却不能操作window对象的属性与方法,所以这个window是没什么用.

场景需求 : www.csdn.cn/a.html页面有个iframe,该iframe的src指向http://csdn.cn/b.html。显然这个a.html与这个iframe不是一个域,无法通过js来获取iframe里面的东西.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// a.html
document.domain='csdn.cn';//设置主域
function loading(){
var iframe = document.getElementById('b');
var window = iframe.contentWindow;//获取iframe的window对象
var document = window.document;//获取iframe的document
}

//b.html

1
2
3
document.domain='csdn.cn';
  • document.domain的设置原则:
    document.domain在这里只能设置成自身的域或者更高一级的父域.
1
2
wrie.a.log.com的domain可以设置为 wrie.a.log.com, a.log.com的,
log.com;

document.domain更适合不同子域的框架交互

如果想通过ajax来获取不同域的资源,用iframe也可以.

1
原理: 在你当前页面a.html用一个iframe标签做代理.通过src引入你打算用ajax获取数据那个目标页面(b.html)同一目录下的任意页面(假设c.html).再通过设置document.domain都相等.这个时候当前页面a.html就可以通过iframe获取到那个c.html页面,我们在用这个iframe向目标页面b.html发送ajax就不存在限制了。相当于转换下思路.

window.name (单向跨域)

在一个window的存活周期内,窗口载入的所有页面都共享一个window.name属性,每个页面对它都具有读写权限,即便window.location重载,也还是一样不会变化.

window.name必须是字符串,更多时候我们设成json格式的字符串,它的大小最大2M.

测试:

1
2
3
4
5
6
7
8
9
10
11
12
// D:\学习资料\NOde\my-vue/a.html
window.name = '这是a设置的';
setTimeout(function(){
window.location = 'b.html';
}, 2000);

在编辑:

1
2
3
4
5
//D:\学习资料\NOde\my-vue/b.html
console.log(window.name);

结果:

这里写图片描述

再来个通过window.name进行跨域获取数据

场景需求: www.csdn.cn/a.html获取www.node.cn/b.html的数据

编辑b.html

这里写图片描述

编辑a.html

原理:用一个iframe作为代理,并设置src指向目标地址.也就是通过iframe来获取目标数据.这时候我们还是不可以在a.html通过iframe获取到b.html里面的window.name,必须把iframe的src设置为a.html的同一个域才可以.

这里写图片描述

window.postMessage (双向跨域)

H5新特性:可以向其他同源或者不同源的window对象发送数据.

浏览器支持度还可以.目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。

  • 格式
1
2
3
4
5
window.postMessage(message , targetOrigin);
// message: 要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化
//targetOrigin: 字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"

场景需求:www.csdn.cn/a.html向www.node.cn/b.html发送消息
编辑a.html

这里写图片描述

编辑b.html进行接受消息

这里写图片描述

通过服务代理 server proxy

在数据提供方没有提供对JSONP协议或者 window.name协议的支持,也没有对其它域开放访问权限时,我们可以通过server proxy的方式来抓取数据.

场景需求:www.a.com/a.html请求www.b.com/data.html。

1
2
给www.a.com配一个代理,比如www.a.com/proxy/这个路径,在把Ajax请求绑定到这个路径,再通过代理发送HTTP请求访问data.html,所以这些都是发生在服务器,客户端不存在跨域Ajax。

转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn

未经允许不得转载:演道网 » JS跨域解决方案详解 -演道网

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册