关于跨域的5种解决方案的知识

跨域

同源策略
首先从同源策略开始讲
----何谓同源:相同的域名、相同的协议、相同的端口即为同源,若有其一不同则视为不同域。

----同源策略带来的限制:
1.cookie、localstorage、indexDB无法读取
2.DOM和JS对象无法读取
3.AJAX请求无法发送;

有时需要跨域请求资源,那么对于这一需求,有什么办法解决同源策略的限制呢?
1. jsonp(jsonp with padding)
jsonp和json的区别:
----json返回的的是一串数据;jsonp返回的是脚本代码
----jsonp只能用get请求,不能用post请求
在JS中,XMLHttpRequest对象无法直接请求跨域的资源,但是在页面上引入不同域上的JS脚本文件是可以的。jsonp利用该特性,具体实现思路是:在页面添加一个script标签 ,利用SRC属性获取对指定地址的请求,这点就类似是get请求。该请求会返回一个JS文件,文件载入成功后会执行在src的URL中指定的函数,并且会把需要的json数据作为参数传入。

<script>
 function doSomething(jsonData) {
     ...................
}
</script>
<script src="http://example.com/data.php?callback=doSomething"></script>

利用jQuery实现jsonp
jQuery会自动生成一个全局函数替换callback=?中的问号,在获取到数据后会自动销毁。而$.getJSON方法会自动判断是否跨域,不跨域就会调用普通的ajax方法;若是跨域会以异步加载JS文件的形式来调用jsonp的回调函数。

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

具有src属性的标签都可以实现跨域

2. CORS(cross-origin resource sharing)
cors分为简单请求和非简单请求
简单请求满足的条件:
---- 使用特定的请求方式如head、get、post
----并且请求头信息为:accept、accept-language、content-language、last-event-ID、content-type
普通跨域请求:服务器设置Access-Control-Allow-Origin即可。
带cookie请求的:前后端都要设置字段。
特点
—cors支持所有类型的http请求,大多数浏览器支持cors除了IE6、IE7
—可以使用普通的XMLHttpRequest发起请求和获得数据,比jsonp有更好的错误处理
实现的思路:使用自定义的http头部,服务器根据浏览器的origin值来决定是否同意此次请求。

  浏览器请求头:Origin: http://foo.example
  服务器响应: Access-Control-Allow-Origin: http://foo.example[*]   //表明可以被来自http://foo.example的域访问[若为*,表示可以被任意外域访问]

简单请求是使用特定的方式请求数据;非简单请求使用设定的方式请求数据之前先发送一个options请求,试探服务器是否允许客户端发送非简单请求,预检通过后会再一次发送请求用于数据传输,如下图:
在这里插入图片描述
详细介绍:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

3. document.domain+iframe
跨域一般分为:一种xhr不能访问不同源的文档,一种是不同的window之间是不可以进行交互操作的如页面中嵌入的iframe。
document.domain解决的是不同window之间不可以交互操作的情况。
案例:现在有一个页面A,地址是http://example.com/a.html,在该A页面中有一个 iframe,它的src是B页面的地址http://example.com/b.html,A页面与iframe是不同域的,所以现在带来的问题是无法在A页面中书写JS代码获取iframe中的内容

A页面
<script>
   function test() {
          var  iframe = document.getElementById('iframe');
          var win = document.contentWindow;
          var  doc = win.document;  //获取不到
          var name = win.name;  //获取不到
   }
   </script>
   <iframe id="iframe" src="http://example.com/b.html" onload="text()"></frame>

解决办法:在A页面的http://example.com/a.html和http://example.com/b.html的document.domain都设为相同的域名即可。如下:

A页面
<script>
document.domain=‘example.com’; //设为主域!!!!
   function test() {
   //可以打印出
         console.log(document.getElementById('iframe').contentWindow);
   }
   </script>
   <iframe id="iframe" src="http://example.com/b.html" onload="text()"></frame>
B页面
<script>
document.domain="example.com"; // iframe载入的B页面的JS中也设置domain
   function testB() {
   }
   </script>

注意:document.domain 的设置是有限制的,只能将domain设置为自身或者更高一级的父域,并且主域要相同,如上述的example.com是主域,如果设置为baidu.com则主域就不相同了。

4. window. name+iframe
window对象有个name属性,name属性的特征是在一个窗口的生命周期内,窗口载入的所有的页面会共享一个 window.name,每个页面都可以对window.name进行读写。
特点:兼容所有的浏览器; window中所有的页面都可以进行修改;window.name的值只可以是字符串的形式,最大是2M的容量。

A页面
<script>
window.name="我是A页面设置的值";
setTimeout(function() {
       window.location="b.html"
},3000);
</script>
B页面
<script>
alert(window.name);
</script>

如何实现跨域?假设现在A页面是 www. example. com/a.html。需要利用A页面中的JS获取不同域的B页面 www. csdn. com/b.html中的window. name的值。
b.html代码如下:

<script>
window.name="我是A想要的数据";
</script>

要实现在A页面中不跳转获取到B页面的数据的解决办法:1.在A页面中嵌入iframe。利用iframe获取b.html的数据,然后A再从iframe中获取到想要的数据。
2. iframe要获取到 b.html的数据需要将 iframe标签的 src设置为B页面的地址 www. csdn. com/b.html。3. 需要再将 iframe的src属性设为与A页面同一个域的页面地址( 因为页面中嵌入的iframe和该页面不属于同源)。4. 然后在A页面的 JS代码里处理从B页面获取的数据,处理数据的代码完毕。
A页面代码如下:

A页面
<script>
var  state = 0;//设置标志位来进行iframe与A页面同源的操作。
function getData(){
      var iframe = document.getElementById('proxy');
      iframe.onload = function() {
          if(state===0){
                        iframe.src = "http://www.example.com/proxy.html"; //与A页面同源的某个代理页面,内容可以为空
                        state = 1;
          }else if(state===1){
                  var data = iframe.contentWindow.name;  //利用iframe的window.name获取B页面中设置的数据
                  console.log(data);   //打印出“我就是A想要的数据”
                  destroyIframe();  //调用函数销毁iframe
            }
      }
      
      function  destroyIframe() {
                   iframe.contentWindow.close(); //处理完毕后最好关闭iframe,释放内存
                  iframe.contentWindow.close();
                  document.body.removeChild(iframe);
      }
 }
<body>
<iframe id='proxy' src="http://csdn.com/b.html" style="display:none" onload="getData()"></iframe>
</body>

proxy.html页面:

proxy.html 代理页
内容可以为空
  1. postMessage
    HTML5引入的新特性,用于:页面和新打开的窗口的数据传递;多窗口之间消息传递;页面与嵌入的iframe消息传递。
    用法:postMessage(data,origin)
    data:传递的数据,最好用JSON.stringify()进行序列化,部分浏览器只支持字符串。
    origin:协议+主机(http默认为www)+端口或者设置为*表示传递给任意窗口;如指定与当前窗口同源设置“/”。
A页面www.domain2.com/a.html
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>       
    var iframe = document.getElementById('iframe');
    iframe.onload = function() {
        var data = {
            name: 'aym'
        };
        // 向domain2传送跨域数据!!!!
        iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
    };
B页面www.domain2.com/b.html
<script>
    // 接收domain1的数据
    window.addEventListener('message', function(e) {
        alert('data from domain1 ---> ' + e.data);

        var data = JSON.parse(e.data);
        if (data) {
            data.number = 16;

            // 处理后再发回domain1
            window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
        }
    }, false);
</script>

参考资料:
https://blog.csdn.net/tjcjava/article/details/76468225
https://www.cnblogs.com/2050/p/3191744.html
前端常见跨域解决方案(全)http://www.cnblogs.com/roam/p/7520433.html

猜你喜欢

转载自blog.csdn.net/Qian_mos/article/details/84851207
今日推荐