我的前端学习笔记26——跨域

1,什么是同源策略

同源策略:
浏览器处于安全方面的考虑,只允许与本域下的接口交互,不同源的客户端脚本在没有明确授权的情况下,不能读取对方的资源。

  • 同协议:(http、file、shh、https、tel、ftp...)以上协议必须相同;
  • 同域名:第一个 // 到第二个 / 之间的部分必须相同;
  • 同端口:一般为80,具体看设置。

以上三条都相同则为同源。

2,什么是跨域?跨域有几种实现形式

  • 跨域:
    在使用ajax向后台请求数据时,如果接口域名不相同,即为跨域。
    换句话说,允许不同域的接口进行交互即为跨域。

  • 跨域实现形式:

  • JSONP

  • CORS

  • 降域

  • postMessage

3,JSONP 的原理是什么

应用中我们发现,使用<script>标签引用链接不会出现跨域问题,因此,可以采用这种方式跨域。<script src='链接 '></script>。服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。

4,CORS是什么

  • CORS:跨域资源共享(Cross-origin resource sharing)
    它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
  • 实现方式:
    当你使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该相应头中是否包含Origin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。

转载自:阮一峰博客

5,根据视频里的讲解演示三种以上跨域的解决方式

  • 方法一:JSONP
  • 优势:
  • 不需要AJAX,只需要通过script标签即可完成向后台发送请求并获取数据;
  • 劣势:
  • 需要后台支持输出指定格式的内容,比如下面例子中的函数名需要后台进行配合;

html端:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>新闻加载example</title>
    <style media="screen">
      .newsFrame{
        margin: 0 auto;
      }
    </style>
  </head>
  <body>
    <div class="newsFrame">
      <ul class="content">
        <li>在北大听讲座</li>
        <li>统计陷阱</li>
        <li>浅薄</li>
      </ul>
      <button class="btn">换一批</button>
    </div>


     <script type="text/javascript">
        $('.btn').addEventListener('click',function(){
          var script = document.createElement('script');
          script.src='http://b.har.com:8080/getNews?callback=appendhtml';

    //当点击按钮时,会在head中生成一个script标签,并下载标签中引用的链接内容。
    //返回的是appendhtml(内容),这个会被函数appendhtml执行,放在html上。

          document.head.appendChild(script);
          document.head.removeChild(script);
        })
    //为了避免生成太多script标签,生成之后立刻删除,但是内容已经下载,不会影响。

      function appendhtml(news){
        var html = '';
        for(var i=0; i<news.length; i++){
          html += '<li>' + news[i] + '</li>'
        }
        console.log(html)
      $('.content').innerHTML = html
      }

      function $(id){
        return document.querySelector(id)
      }

    </script>
  </body>
</html>

后台端:

app.get('/getNews', function(req, res) {

        var news = [
        "身边的逻辑学",
        '牛奶可乐经济学',
        '看见',
        '论中国',
        '乌合之众',
        '哲学的慰藉'
      ]
      var data = [];
      for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
      news.splice(index,1);
      }
    var cb = req.query.callback;
      res.send( cb + '(' + JSON.stringify(data) + ')' );
    });
    //获取callback的内容(函数名称),包装之后返回给html。
  • 方法二:CORS

  • 优势:

  • 整个过程无需用户参与,完全由浏览器自己完成;

  • 只需要在后台加入响应头即可,不需要对ajax进行复杂变换;

  • 劣势:

HTML端:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>新闻加载example</title>
    <style media="screen">
      .newsFrame{
        margin: 0 auto;
      }
    </style>
  </head>
  <body>
    <div class="newsFrame">
      <ul class="content">
        <li>在北大听讲座</li>
        <li>统计陷阱</li>
        <li>浅薄</li>
      </ul>
      <button class="btn">换一批</button>
    </div>


     <script type="text/javascript">
        $('.btn').addEventListener('click',function(){

          var xmlhttp = new XMLHttpRequest();
          xmlhttp.open('get','http://b.har.com:8080/getNews',true);
          xmlhttp.send();

          xmlhttp.onreadystatechange = function(){
            if(xmlhttp.readyState==4 && xmlhttp.status==200){
              appendhtml(JSON.parse(xmlhttp.responseText));
            }
          }


        })

      function appendhtml(news){
        var html = '';
        for(var i=0; i<news.length; i++){
          html += '<li>' + news[i] + '</li>'
        }
        console.log(html)
      $('.content').innerHTML = html
      }

      function $(id){
        return document.querySelector(id)
      }

    </script>
  </body>
</html>

后台端:

app.get('/getNews', function(req, res) {

        var news = [
        "身边的逻辑学",
        '牛奶可乐经济学',
        '看见',
        '论中国',
        '乌合之众',
        '哲学的慰藉'
      ]
    var data = [];
    for(var i=0; i<3; i++){
      var index = parseInt(Math.random()*news.length);
      data.push(news[index]);
      news.splice(index,1);
    }
    // res.head('Access-Control-Allow-Origin','http://a.har.com:8080')
    //注意这里是a.har.com:8080,因为后台端是在b.har.com域下
    res.header("Access-Control-Allow-Origin","*");
    res.send(data);
  });
  • 方法三:降域

  • 优势:

  • 代码超级简单,只需一个命令就轻松搞定;

  • 劣势:
    只能在拥有相同父域名下才可以使用;

a.har.com端:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>降域test</title>
    <style media="screen">
      .main{
        border: 1px solid #ccc;
        width:500px;
        height: 500px;
        display: inline-block;
        position: absolute;
        top:10px;
        left:10px;
      }
      iframe{
        border: 1px dashed #ccc;
        width:500px;
        height:500px;
        margin-left: 100px;
        position: absolute;
        top:10px;
        left:450px;
      }
    </style>
  </head>
  <body>
    <div class="ct">
      <div class="main">
        <h1>使用降域来实现跨域</h1>
        <input type="text" class="content" placeholder="http://a.har.com:8080">
      </div>
      <iframe src="http://b.har.com:8080/jiangyu2.html" frameborder="0"></iframe>
    </div>
    <script type="text/javascript">
      document.querySelector('.main input').addEventListener('input',function(){
        console.log(this.value);
        window.frames[0].document.querySelector('input').value = this.value;
      })
      document.domain = 'har.com';
      //降域的命令;
    </script>
  </body>
</html>

b.har.com端:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>降域test2</title>
    <style media="screen">
  </style>
  </head>
  <body>
    <div class="ct">
      <h1>使用降域来实现跨域</h1>
      <div class="main">
        <input type="text" class="content" placeholder="http://a.har.com:8080">
      </div>
    </div>
    <script type="text/javascript">
      document.querySelector('.main input').addEventListener('input',function(){
        window.parent.document.querySelector('input').value = this.value;
      })
      document.domain = 'har.com';
      //降域的命令;
    </script>
  </body>
</html>

-方法四:postMassage

  • 优势:
  • 域名完全不相同也没关系;
  • 劣势:
  • 操作真心复杂;

a.har.com:8080/postMessage端:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>降域test</title>
    <style media="screen">
      .main{
        border: 1px solid #ccc;
        width:500px;
        height: 500px;
        display: inline-block;
        position: absolute;
        top:10px;
        left:10px;
      }
      iframe{
        border: 1px dashed #ccc;
        width:500px;
        height:500px;
        margin-left: 100px;
        position: absolute;
        top:10px;
        left:450px;
      }
    </style>
  </head>
  <body>
    <div class="ct">
      <div class="main">
        <h1>使用postMessage来实现跨域</h1>
        <input type="text" class="content" placeholder="http://a.har.com:8080">
      </div>
      <iframe src="http://b.har.com:8080/postMessage2.html" frameborder="0"></iframe>
    </div>
    <script type="text/javascript">
      document.querySelector('.main input').addEventListener('input',function(){
        console.log(this.value);
        window.frames[0].postMessage(this.value,'*');
      })
      window.addEventListener('message',function(e){
        document.querySelector('.main input').value = e.data;
      })
    </script>
  </body>
</html>

b.har.com:8080/postMessage2端:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>降域test2</title>
    <style media="screen">
  </style>
  </head>
  <body>
    <div class="ct">
      <h1>使用postMessage来实现跨域</h1>
      <div class="main">
        <input type="text" class="content" placeholder="http://a.har.com:8080">
      </div>
    </div>
    <script type="text/javascript">
      document.querySelector('.main input').addEventListener('input',function(){
        window.parent.postMessage(this.value,'*');
      })
      window.addEventListener('message',function(e){
        document.querySelector('.main input').value = e.data;
        console.log(e.data);
      })
    </script>
  </body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容