什么是跨域?如何解决跨域问题?

###什么是跨域?
浏览器从一个域名的网页去请求另外一个域名的资源时,域名、端口、协议任一不一样,都是跨域
域名:
 主域名不一样 http://www.baidu.com/index.html -->http://www.sina.com/test.js
 子域名不一样 http://www.666.baidu.com/index.html -->http://www.555.baidu.com/test.js
 域名和域名ip http://www.baidu.com/index.html -->http://180.149.132.47/test.js
端口:
 http://www.baidu.com:8080/index.html--> http://www.baidu.com:8081/test.js
协议:
 http://www.baidu.com:8080/index.html--> https://www.baidu.com:8080/test.js
备注:
 一、端口和协议的不一样,只能经过后台来解决
 二、localhost和127.0.0.1虽然都指向本机,但也属于跨域
###如何解决跨域问题?
一、jsonp跨域
JSONP(JSON with Padding:填充式JSON),应用JSON的一种新方法,
JSON、JSONP的区别:
 一、JSON返回的是一串数据、JSONP返回的是脚本代码(包含一个函数调用)
 二、JSONP 只支持get请求、不支持post请求
 (相似往页面添加一个script标签,经过src属性去触发对指定地址的请求,故只能是Get请求)javascript

二、nginx反向代理:
  www.baidu.com/index.html须要调用www.sina.com/server.php,能够写一个接口www.baidu.com/server.php,由这个接口在后端去调用www.sina.com/server.php并拿到返回值,而后再返回给index.html
三、PHP端修改header
  header(‘Access-Control-Allow-Origin:*’);//容许全部来源访问
  header(‘Access-Control-Allow-Method:POST,GET’);//容许访问的方式
4、document.domain
跨域分为两种,一种xhr不能访问不一样源的文档,另外一种是不一样window之间不能进行交互操做;
  document.domain主要是解决第二种状况,且只能适用于主域相同子域不一样的状况;
  document.domain的设置是有限制的,咱们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com中某个文档的document.domain能够设成a.b.example.comb.example.com 、example.com中的任意一个,可是不能够设成c.a.b.example.com,由于这是当前域的子域,也不能够设成baidu.com,由于主域已经不相同了。
兼容性:全部浏览器都支持;
优势:
 能够实现不一样window之间的相互访问和操做;
缺点:
 只适用于父子window之间的通讯,不能用于xhr;
 只能在主域相同且子域不一样的状况下使用;
使用方式:
 不一样的框架之间是能够获取window对象的,但却没法获取相应的属性和方法。好比,有一个页面,它的地址是http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不一样域的,因此咱们是没法经过在页面中书写js代码来获取iframe中的东西的:php

<script type="text/javascript">
    function test(){
        var iframe = document.getElementById('ifame');
        var win = document.contentWindow;//能够获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
        var doc = win.document;//这里获取不到iframe里的document对象
        var name = win.name;//这里一样获取不到window对象的name属性
    }
</script>
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>

这个时候,document.domain就能够派上用场了,咱们只要把http://www.example.com/a.html 和 http://example.com/b.html这两个页面的document.domain都设成相同的域名就能够了。
1.在页面 http://www.example.com/a.html 中设置document.domain:html

<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
<script type="text/javascript">
    document.domain = 'example.com';//设置成主域
    function test(){
        alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
    }
</script>

2.在页面 http://example.com/b.html 中也设置document.domain:前端

<script type="text/javascript">
    document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
</script>

5、window.name
关键点:window.name在页面的生命周期里共享一个window.name;
兼容性:全部浏览器都支持;
优势:
 最简单的利用了浏览器的特性来作到不一样域之间的数据传递;
 不须要前端和后端的特殊配制;
缺点:
 大小限制:window.name最大size是2M左右,不一样浏览器中会有不一样约定;
 安全性:当前页面全部window均可以修改,很不安全;
 数据类型:传递数据只能限于字符串,若是是对象或者其余会自动被转化为字符串,以下;
 这里写图片描述
使用方式:修改window.name的值便可;
6、postMessage
关键点:
 postMessage是h5引入的一个新概念,如今也在进一步的推广和发展中,他进行了一系列的封装,咱们能够经过window.postMessage的方式进行使用,并能够监听其发送的消息;
兼容性:移动端能够放心用,可是pc端须要作降级处理
优势
 不须要后端介入就能够作到跨域,一个函数外加两个参数(请求url,发送数据)就能够搞定;
 移动端兼容性好;
缺点
 没法作到一对一的传递方式:监听中须要作不少消息的识别,因为postMessage发出的消息对于同一个页面的不一样功能至关于一个广播的过程,该页面的全部onmessage都会收到,因此须要作消息的判断;
安全性问题:三方能够经过截获,注入html或者脚本的形式监听到消息,从而可以作到篡改的效果,因此在postMessage和onmessage中必定要作好这方面的限制;
 发送的数据会经过结构化克隆算法进行序列化,因此只有知足该算法要求的参数才可以被解析,不然会报错,如function就不能看成参数进行传递;
使用方式:通讯的函数,sendMessage负责发送消息,bindEvent负责消息的监听并处理,能够经过代码来作一个大体了解;java

Storage.prototype.sendMessage_ = function(type, params, fn) {
    if (this.topWindow) {
        this.handleCookie_(type, params, fn);
        return;
    }
    var eventId = this.addToQueue_(fn, type);
    var storageIframe = document.getElementById('mip-storage-iframe');
    var element = document.createElement("a");
    element.href = this.origin;
    var origin = element.href.slice(0, element.href.indexOf(element.pathname) + 1);
    storageIframe.contentWindow.postMessage({
        type: type,
        params: params,
        eventId: eventId
    }, origin);
}
Storage.prototype.bindEvent_ = function() {
    window.onmessage = function (res) {
        // 判断消息来源
        if (window == res.source.window.parent &&
            res.data.type === this.messageType.RES &&
            window.location.href.match(res.origin.host).length > 0) {
            var fn = this.eventQueue[res.data.eventId];
            fn && fn();
            delete this.eventQueue[res.data.eventId];
            // reset id
            var isEmpty = true;
            for (var t in this.eventQueue) {
                isEmpty = false;
            }
            if (isEmpty) {
                this.id = 0;
            }
        }
    }.bind(this);
}