javaScript——浅谈跨域的概念和几种跨域的方法

1. 跨域的概念即什么情况下会发生跨域

一个网站的网址组成包括协议名,子域名,主域名,端口号。比如 https://github.com/ ,其中https是协议名,www是子域名,github是主域名,端口号是80,当在在页面中从一个url请求数据时,如果这个url的协议名、子域名、主域名、端口号任意一个有一个不同,就会产生跨域问题。

2. 跨域存在的形态

2.1 Ajax

不同域之间是数据传递

2.2 Cookie

访问不同域的cookie信息

2.3 Iframe

不在同一域的父子窗口的DOM操作

3. 如何处理跨域

3.1 Ajax:

3.1.1 Jsonp:客户端方法

  • 原理:

在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。

Dosomething函数实现约定好

"http://xxx.xxx.xxx"为请求数据的地址

1

2

3

4

5

6

7

<script type="text/javascript">

    function dosometing(jsondata)

    {

        //处理json数据

    }

</script>

<script src="http://xxx.xxx.xxx?callback=dosometing"></script>

  • 应用:

在实际应用中可以使用js动态的生成script标签来进行跨域

1

2

3

4

5

6

<script type="text/javascript">

    var url ="http://xxx.xxx.xxx?callback=dosometing",

            script = document.createElement('script');

    script.setAttribute('src',url);

    document.getElementsByTagName('head')[0].appendChild(script);

</script>

在使用jQuery的情况下可以使用$.getJSON方法,$.getJSON方法会自动判 断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步 加载js文件的形式来调用jsonp的回调函数。

1

2

3

4

5

<script type="text/javascript">

    $.getJSON('http://xxx.xxx.xxx?callback=dosometing',function(){

        //处理获得的json数据

    })

</script>

或者

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<script type="text/javascript">

    $.ajax({

        async : false,

        url : "http://xxx.xxx.xxx",

        type : "GET",

        dataType : "jsonp",

        jsonp : 'callback',//约定好的函数

        data :null,//传递的参数,没有参数也要传

        timeout:5000,

        contentType : "application/json;utf-8",

        success: function(result){

             

        },

        error : function(){

             

        }

    })

</script>

  • JSONP的优缺点:

JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。

JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题(用于传递数据)。

  • 拓展:拥有src这个属性的标签都具有跨域的能力(img、script、iframe)

3.1.2 Cors(跨域资源共享):服务器端方法

  • 原理:

CORS定义一种跨域访问的机制,可以让AJAX实现跨域访问。CORS 允许一个域上的网络应用向另一个域提交跨域 AJAX 请求。实现此功能非常简单,只需由服务器发送一个响应标头即可。

  • 应用:

服务器:

在Apache配置文件的<Directory>, <Location>, <Files>或<VirtualHost>的配置里加入以下内容即可:

Header set Access-Control-Allow-Origin *

PHP:

<?php   header("Access-Control-Allow-Origin:*")>;*号表示允许任何域向我们的服务端提交请求;

也可以设置指定的域名,那么就只允许来自这个域名的请求

header("Access-Control-Allow-Origin: http://www.xxx.xx")

  • 浏览器支持

3.2 Cookie

可使用ajax和iframe处理跨域的方式解决

3.3 Iframe

3.3.1 window.name实现跨域数据传输

  •  原理:

一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。

  •  应用:

三个页面:

 a.com/app.html:应用页面。

 a.com/proxy.html:代理文件,一般是一个没有任何内容的html文件,需要和应用页面在同一域下。

 b.com/data.html:应用页面需要获取数据的页面,可称为数据页面。

实现的步骤:

1.在应用页面中创建一个iframe,并把src指向数据页面;设置数据后再将iframe的src设置为与app.html同域的proxy.html。

Data.html:

1

2

3

<script type="text/javascript">

    window.name = " value";//这里传递的数据可以是json、字符串等等

</script>

app.html

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

<script type="text/javascript">

    var state = 0,

            iframe = document.createElement('iframe'),

            loadfn = function(){

                if(state === 1)

                {

                    var data = iframe.contentWindow.name;//读取数据

                    alert(data);//弹出"value"

                }else if(state === 0)

                {

                    state = 1;

                    iframe.contentWindow.location = "http://xxx.xxx.xxx.html";//设置代理文件

                }

            };

    iframe.src = 'http://b.com/data.html';

    if(iframe.attachEvent()){

        iframe.attachEvent('onload',loadfn);

    }else{

        iframe.onload = loadfn;

    }

    document.body.appendChild(iframe);

</script>

3.3.2 利用iframe和location.hash

  •  原理:

在url: a.com#helloword中的‘#helloworld’就是location.hash,改变hash并不会导致页面刷新,所以可以利用hash值来进行数据传递。

  •  应用:与window.Name类似

app.htm页面通过iframe到data.htm中,由b.htm控制,看下图:  现在的关系为,app.htm中iframe加入了data.htm,data.htm页面中iframe加入了Proxy.html

Location.hash的应用与window.name类似:各页面主要操作如下

App.html:

var data = location.hash ? location.hash.substring(1) : '';

Proxy.html:

parent.parent.location.hash = window.location.hash//获取data传递过来的数据

data.html

parent.location.hash = 'somedata'

  •  缺点:缺点是只支持string类型,大小受限制

3.3.3 document.domain实现跨子域

主域相同子域不同的页面,可以通过为两页面设置相同的document.domain来实现跨域,但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。

  • 应用:

www.example.com/a.html中设置domain

1

2

3

4

5

6

<script type="text/javascript">

    document.domain = 'example.com';//设置主域

    function test(){

        alert(document.getElementById("iframe").contentWindow);//contentWindow可获取子窗口的window对象

    }

</script>

example.com/b.html中设置domain

1

2

3

<script type="text/javascript">

    document.domain = 'example.com';//设置主域

</script>

3.3.4 window.postMessage实现跨域

  •  了解postmessage

otherWindow.postMessage(message, targetOrigin);

otherWindow: 要接收消息的那一个window对象

message: 所要发送的数据,string类型。

targetOrigin: 用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 *  。

  • 应用:

a.com

1

2

3

4

5

6

7

8

9

<iframe id="ifr" src="b.com/index.html" onload="test()"></iframe>

<script type="text/javascript">

    window.onload = function()

    {

        var ifr = document.getElementById("ifr");

        var targetOrigin = 'http://b.com';

        ifr.contentWindow.postMessage('message',targetOrigin);

    }

</script>

b.com

1

2

3

4

5

6

7

8

9

10

11

<script type="text/javascript">

    window.addEventListener('message',function(event){

        //通过origin属性判断消息来源

        if(event.origin == 'http://a.com')

        {

            alert(event.data);//弹出‘to b’

            alert(event.source)//对a.html、index.html中window对象的引用,但由于同源策略,这里event.source不可访问window对象

             

        }

    },flase);

    </script>

4. 跨域的安全问题

相关链接:

Cors原理:http://newhtml.net/using-cors/

猜你喜欢

转载自blog.csdn.net/qq_42269433/article/details/81135840