浅聊浏览器跨域的问题
什么是跨域,可以做个试验。假如你先做看文章用的是谷歌浏览器,可以打开开发者工具,在console中输入:
$.post('https://www.baidu.com');
会发现控制台报错『XMLHttpRequest cannot load…』。
为什么会出现上述问题呢?原因是由于浏览器的同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,所以AJAX是不允许跨域的。像<script>,<link>,<img>,<iframe>这些标签是允许跨域的,但你并不能修改这些资源,比如iframe里的内容。
跨域分为两种,一种xhr不能访问不同源的资源,另一种是不同window之间不能进行交互操作。
那么浏览器为什么会有同源策略限制呢?还是举个简单的例子,假如有个黑客,自己做了个页面,嵌入了一个iframe,iframe内是银行的登录页面,假如没有同源策略限制,那么他就可以通过JavaScript来拿到你输入的内容了。
以下的几种情况,都算是跨域:
- 协议不同,如http, https;
- 端口不同;
- 主域相同,子域不同,例如a.baidu.com和b.baidu.com;
- 主域不同;
- ip地址和域名之间也算是跨域,浏览器不会自动做ip域名的映射;
实际的工作中,偶尔也会遇到跨域的问题,下面来介绍下,如何解决跨域的问题:
- document.domain
- window.name + iframe
- location.hash + iframe
- jsonp
- postMessage
- cors
- 同域代理
1. document.domain
- 说明:document.domain主要解决不同window对象之间,主域相同而子域不同的情况。document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com中某个文档的document.domain可以设成a.b.example.com、b.example.com 、example.com中的任意一个,但是不可以设成c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。
- 兼容性:所有的浏览器都支持.
- 优点:可以实现不同window之间的相互访问和操作;
- 缺点:只适用于父子window之间的通信,不能用于xhr,并且只能在主域相同且子域不同的情况下使用;
- 使用方式:a(当前页面或父页面)页面中加入document.domain = ‘example.com’;b(当前页面或子页面)页面中加入document.domain = ‘example.com’;a页面访问b页面里面的数据或者方法;
2. window.name + iframe.
- 说明:这个实现起来就稍微有些麻烦了,需要内部窗口配合,来将需要跨域传递的值赋值给window.name,然后在父窗口中,读取iframe的window.name来实现跨域访问。
- 兼容性:所有浏览器都支持。
- 优点:兼容所有浏览器。
- 缺点:首先大小最多支持2M。然后只支持字符串,实现起来比较复杂。
- 使用方式:内部窗口通过js设置window.name,外部窗口轮询window.name来获取内部窗口数据.
3. location.hash + iframe
- 说明:和2差不多,内部窗口将值放到location.hash中,外部窗口通过url来获取要传递的值。
- 兼容性:兼容所有浏览器
- 优点:兼容所有浏览器
- 缺点:受到Url长度的限制,中文需要转义,最严重的是会产生访问记录,安全性会有一定问题。
- 使用方式:内部窗口将值放到location.hash中,外部窗口通过url来获取要传递的值。
4. jsonp
- 说明:浏览器对于不同域的script是没有同源策略限制的。比如w3cstart就内嵌了百度的统计的代码。可以利用这个特性来实现跨域的请求。A域发送一个请求到B域,然后B域返回一段可执行的js脚本,同时在脚本内将数据回传给A域,并调用A域中的方法来执行后续操作。
- 兼容性:兼容所有浏览器
- 优点:使用简单,很多框架对其进行支持,是主流的跨域方案之一。
- 缺点:1.只能通过GET方式请求,参数长度有限制。2.后端需要知道前端的cb是什么样的结构,主要在参数和回调名;3.后端需要进行参数和cb的拼接然后才能执行;
5. postMessage
- 说明:html5引入的message的API可以更方便、有效、安全的解决跨域难题。
- 兼容性:移动端可以放心用,但是pc端需要做降级处理,具体可以根据文中介绍的这几种跨域方式来则情选择。
- 优点:实现方便,一个函数外加两个参数(请求url,发送数据)就可以搞定,而且移动端兼容性好。
- 缺点:消息类似于广播的形式进行分发,需要在广播中对事件进行判断。如果处理不好,第三方可以通过截获,注入html或者脚本的形式监听到消息,从而能够做到篡改的效果,所以在postMessage和onmessage中一定要做好这方面的限制。
- 使用方式:http://test.com/index.html页面中代码如下:
<div> <iframe id="child" src="http://lsLib.com/lsLib.html%26 ... gt%3B</div>
我们可以在http://test.com/index.html通过postMessage()方法向跨域的iframe页面http://lsLib.com/lsLib.html传递消息
window.onload=function(){ window.frames[0].postMessage('getcolor','http://lslib.com'); } http://lslib.com/lslib.html这个页面中,我们可以通过message事件来进行处理
window.addEventListener('message',function(e){ if(e.source!=window.parent) return; var color=container.style.backgroundColor; window.parent.postMessage(color,'*'); },false);
6. CORS
说明:cors是一种通过前后端http header配置来进行跨域的一种方式,服务端设置response的头,返回Access-Control-Allow-Origin: origin,origin表示允许哪些网站请求,不建议设置为*;
兼容性:PC端不兼容IE,移动端不兼容Opera。
优点:前端可以做到透明,只需要发请求而不用考虑跨域问题;安全性能够得以控制和保障;
缺点:兼容性。
7.同域代理
说明:这个勉强也算是跨域的一种解决方案吧,假如需要跨域请求数据,而数据提供方无法做出修改兼容请求方,那么就可以在同域后台加一个转发,请求先发到同域的服务端,然后服务端进行请求,并返回数据。