三十、JS几种跨域方法和原理

Ps:浏览器的同源策略:其限制之一就是不能通过ajax的方法请求不同源中的文档。限制二是浏览器中不同域的框架之间不能进行js的交互操作。
一、什么是跨域?
1.JS跨域是指通过js在不同的域之间进行数据传输或通信,如Ajax向一个不同的域请求数据,或者通过JS获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,即为不同的域;
Eg:网址是  http://baidu.com:8080?user=name&pwd=password
http://  协议
baidu.com 域名(注意:www.baidu.com不是域名)
8080 端口
user=name&pwd=password 地址带的参数
2.在Js中直接使用XMLHttpRequest(Ajax)请求不同域上的数据,是不能实现的;
  Eg:相对http://store.company.com/dir/page.html同源检测的结果:

一、通过jsonp跨域

1.在js中,可以在页面上引入不同域上的js脚本文件,jsonp利用这个特性实现跨域。简单来说,请求的文件只要含有“src”,“href”这些属性,就能在A服务器上请求所需的文件,然后在B服务器上运行,实现跨域。

 

举例:

index.html页面,它里面的代码需要利用ajax获取一个不同域上的json数据,假设json数据地址是http://example.com/data.phpindex.html代码为:

<script>
    function gaindata(jsondata){
        //处理获得的json数据
    }
</script>
//jsonp跨域
<script src="http://example.com/data.php?callback=gaindata"></script>

跨域原理:这里的json数据是被当做js文件通过script标签引入的,(http://example.com/data.php返回的必须是一个能执行的js文件) ,这个js文件载入成功后会执行url参数中指定的gaindata函数,并且会将json数据作为参数传入函数中。

PHP代码:

<?php
  $callback=$_GET[callback];//获取回调函数callback
  $data=array("a","b","c");//设置要返回的数据
  echo $callback."(".json_encode($data).")";//输出数据

2. 通过jsonp跨域原理,可以用js动态生成script标签进行跨域操作。若页面使用jquery,那么通过其封装的方法很方便的进行jsonp操作。

<script>
$.getJSON('http://example.com/data.php?callback=?',function(jsondata){
        //处理获得的json数据
    })
</script>

原理一样,只是jquery会自动生成一个全局函数替换callback=?中的问号,之后获取到的数据又会自动销毁,即是一个临时函数的作用$getJSON方法会自动判断是否跨域,不跨域,就调用普通的ajax方法,跨域,则会以异步加载js文件的形式来调用jsonp的回调函数。

 

二、CORS原理跨域

1.JSONP原理,其不足就是只能使用GET提交,若传输的数据量大,这个JSONP方式就使用不了了,相对JSONP,CORS支持POST提交,并且实施起来灰常简单

2.原理:CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。CORS原理只需要向响应头header中注入Access-Control-Allow-Origin:*(*指任意域),页面进行正常的ajax请求即可,这样浏览器检测到header中的Access-Control-Allow-Origin,则就可以跨域操作了。

 

3.常见后端解决跨域方案:

(1)php后台配置:

第一步:配置Php 后台允许跨域

<?php header('Access-Control-Allow-Origin: *');

header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');

//主要为跨域CORS配置的两大基本信息,Originheaders

第二步:配置Apache web服务器跨域(httpd.conf)

原始代码:

<Directory />

    AllowOverride none

    Require all denied

</Directory>

修改代码:

<Directory />

    Options FollowSymLinks

    AllowOverride none

    Order deny,allow

    Allow from all

</Directory>

 

(2)JAVA后台配置

第一步:获取依赖jar包下载 cors-filter-1.7.jar, java-property-utils-1.9.jar 这两个库文件放到lib目录下。(放到对应项目的webcontent/WEB-INF/lib/)

第二步:如果项目用了Maven构建的,请添加如下依赖到pom.xml:

<dependency>

    <groupId>com.thetransactioncompany</groupId>

    <artifactId>cors-filter</artifactId>

    <version>[ version ]</version>

</dependency>

例如:

<script>

/* 2.CORS跨域 允许浏览器向跨源服务器发送XMLHttpRequest请求*/
    //2-1 通过配置php后台允许跨域
    //header('Access-Control-Allow-Origin:*');
    //header('Access-Control-Allow-Headers:Origin,X-Requested-With,Content-Type,Accept')
    //主要配置Origin和headers
    var ajax=new XMLHttpRequest();
    ajax.open("get","http://localhost:80/ajax0609/php/data2.php");
    ajax.send();
    ajax.onreadystatechange=function (){
        if(ajax.readyState==4&&ajax.status==200)
        {
            console.log(ajax.response);
        }
    }
</script>

 

PHP后端配置:

<?php
      header('Access-Control-Allow-Origin: *');
      $callback=$_GET[callback];
      $data=array("a","b","c");
      echo $callback."(".json_encode($data).")";
      ?>

 

三、通过修改document.domain来跨子域

1.不同的框架之间(父子或同辈),是能够获取到彼此的window对象的,但不能使用获取到的window对象的属性和方法(除h5的postMessage方法)

2.document.domain方法就是将两个界面的document.domain都设置为相同的域名就可以。但是只能设置自身或更高一级的父域,且主域必须相同。且这个方法只适用于不同子域的框架间的交互。

例如:a.b.example.com、b.example.com、example.com中任意一个,但不可以设置成c.a.b.example.com,baidu.com;

 

a.html界面:

<iframe src="https://www.example.com/b.html" id="iframe" οnlοad="test()"></iframe>
<script>
    document.domain='example.com';//设置成主域
    function test(){
        alert(document.getElementById('iframe').contentWindow);
    }
</script>

b.html界面:

<script>   

document.domain='example.com';
</script>

 

四、使用window.name来进行跨域

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

注意:window.name只能是字符串的形式;最大允许2M左右甚至更大的一个容量,具体取决于不同的浏览器,但一般是够用了;

 

例如:a.html和b.html同域的数据交互

a.html

<script>
    window.name='页面1';//设置window.name的值
    setTimeout(function(){
        window.location='index.html';
    },3000);//3秒更新页面index.html载入到当前的window
</script>

index.html

<script>

alert(window.name);//读取window.name的值
</script>


跨域:a.htmldata.html的信息交互  利用iframe获取data.html的数据,然后再去得到iframe获取到的数据;

 

a.html:

<script>
    function getData(){//iframe载入data.html页面后会执行函数
        var iframe=document.getElementById("proxy");
        iframe.onload=function(){//a.html与iframe已处于同一源,可互相访问
            var data=iframe.contentWindow.name;//获取iframe里的window.name,即data.html页面给它设置的数据
            alert(data);//成功获取到data.html里的数据
        };
        iframe.src="b.html";//这是随意的一个页面,只需与a.html同源,能访问到iframe里的东西,设置成about:blank也行
    }
</script>
<iframe src="https://www.example.com/data.html" id="proxy" style="display: none" οnlοad="getData()"></iframe>

 

五、使用H5中新引进的window.postMessage方法来跨域传送数据

1.原理:调用postMessage方法的window对象是指要接收消息的那个window对象,该方法的第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 *

需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。

 

例如:

a.html:

<script>
    function onload() {
        var iframe=document.getElementById("iframe");
        var win=iframe.contentWindow;//获取window对象
        win.postMessage("页面a","*");//向不同域的b.html页面发送消息
    }
</script>
<iframe src="http://www.example.com/b.html" οnlοad="onload()" id="iframe"></iframe>

b.html:

<script>
    window.onmessage=function(){//注册message事件用来接收消息
        e=e||event;//获取事件对象
        alert(e.data);//通过data属性得到传送的消息
    }
</script>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值