记录学习|跨域

301 阅读2分钟

经常被提及的跨域是一种狭义上的跨域,指的是由浏览器的同源策略所限制的一种场景。同源策略(same origin policy),指的是域名、端口号、协议三者相同,他是浏览器最基本的安全策略,可以防范浏览器的CSRF、XSS攻击。

跨域的场景分析

     URL                                说明                     是否允许通信
http://www.juejin.com/a.js
http://www.juejin.com/b.js          相同域名,不同文件/路径             允许
http://www.juejin.com/c/c.js

http://www.juejin.com:8080/a.js     相同域名,不同端口号               不允许
http://www.juejin.com/a.js

http://www.juejin.com/a.js          相同域名,不同协议                 不允许
https://wwww.juejin.com/a.js

http://www.juejin.com               相同协议,不同域名                 不允许
http://www.juejin1.com

http://wwww.juejin.com
http://a.juejin.com                 主域名相同,子域名不相同            不允许
http://a.b.juejin.com

处理跨域的方式

1.JSONP

通过动态创建script,再请求一个带参网址实现跨域通信。JSONP只能实现get。

过程:创建一个script标签、前端生成一个全局函数、服务端返回前端全局函数的调用

原生

   //创建一个script标签
   var script = document.createlement('script');
   script.type = 'text/javascript';
   //前端生成一个全局函数,传参回调函数的名字给后端,方便后端执行时返回这个在前端定义的函数
   script.src = ''http://www.juejin.com/login?user=admin&callback=handleCallBack;
   
   function handleCallBack(res){
       alert(JSON.stringfy(res))
     }
   

服务端返回: handleCallBack({"status":true,"user":"admin"})

vue.js

this.$http.jsonp('http://www.juejin.com/login',{
   params:{};
   jsonp:'handCallBack'
   }).then((res)=>{
     console.log(res)
   })

2.document.domamin + iframe

用来解决主域名相同,子域名不同的跨域问题。

实现原理:两个页面都设置document.domain为基础主域。

1)第一个窗口:www.juejin.com/a.js

   <iframe id='iframe' scr='http://2.juejin.com/a.js' style='display:none'></iframe>
   <script>
      document.domain = 'domain.com';
      var user = admin;
   </script>

2)第二个窗口:2.juejin.com/a.js

  document.domain = 'domain.com'
  console.log(window.parent.user)//获取父窗口中的变量值。

3.location.hash+iframe

a与b不同域,但是想要相互通信,则通过一个中间页面c来实现,三个页面之间相同域的直接用js进行访问通信,不同域之间通过location.hash传值。

1)第一个窗口:www.juejin1.com/a.html

    <iframe id='iframe' src='http://www.juejin2.com/b.html' style='display:none'></iframe>
    <script>
       var iframe = document.getElementById('iframe');
       //给第二个不同域的页面传哈希值
       setTimeout(function(){
         iframe.src = iframe.src+'#user=admin'
       },1000);
       //给第三个同域的页面开放回调
       function callBackFn(res){
          alert('data from third-----'+res);
        }
    </script>

2)第二个窗口:www.juejin2.com/b.html

  <iframe id='iframe' src='http://www.juejin1.com/c.html' ></iframe>
  <script>
      var iframe =document.getElementById('iframe')
      //监听第一个页面传过来的hash值然后传递给第三个页面
      window.onHashChange = function(){
         iframe.src = iframe.src + loction.hash;
      }
  </script>

3)第三个窗口:wwww.juejin1.com/c.html

  <script>
  //监听第二个窗口传过来的hash值
    window.onHashChange = function(){
    //通过操作同域名下的a.html的js回调,并将值传回。
      window.parent.parent.callBackFn('-----'+loction.hash.replace('#user',''))
    }
  </script>

4.跨域资源共享(CORS)

不带cookie请求的时候,只需要后端设置Access-Control-Allow-Origin,带cookie请求的时候,需要前后端都进行设置。需要注意的是,由于同源策略的限制,获取的cookie为跨域请求接口所在域的cookie,而不是当前页的cookie。

前端设置是否带cookie:

vue.js

vue-resource设置: Vue.http.options.credentials = true

axios设置:axios.defaults.withCredentials = true

5.window.name+iframe

name值在不同的页面哪怕是不同的域名加载后都依然存在,并且可支持的name值长达2MB。

6.postMessage

window.postMessage()方法可以安全的实现跨源通信,它可以应用于:

1)页面和其打开的窗口的数据传递

2)多窗口之间消息传递

3)页面与嵌套的iframe消息传递

4)上面三个场景的跨域数据传递

使用方法

postMessage(data,origin)

data:html5接受任意可复制的对象或者任意基本数据类型,但是有的浏览器只接受字符串,所以使用的时候最好先用JSON.stringfy()列化。

origin:协议+主机+端口号。也可以设置为 * 表示任意窗口,如果要指定和当前窗口同源的话设置为 /

a:www.juejin1.com

   <iframe id='iframe' src='http://www.juejin2.com' style='display:none'></iframe>
   <script>
     var iframe = document.getElementById('iframe');
     iframe.onload = function(){
         var data = {
            user :'admin'
          };
     //向juejin2传递跨域数据
     iframe.contentWindow.postMessage(JSON.stringfy(data),'http://www.juejin2.com')
       }
       //接受juejin2返回的数据
       window.addEventListener('message',function(e){
         consloe.log(e.data)
       },false)
   </script>

b:www.juejin2.com

  <script>
   //接受juejin1的数据
    window.addEventListener('message',function(e){
       console.log(e.data);
     
       var data = JSON.parse(e.data);
       if(data){
             data.number =1;
             
        //对数据进行处理,处理之后再发给juejin1             
             window.parent.postMessage(JSON.stringfy('data'),'http://www.juejin1.com')
        }
    },false)
  </script>

7.Nginx代理