九种方式实现跨域

  1. 什么是跨域
    即‘同源策略’。简单说,就是浏览器规定的安全功能。(自行Google,百度看看,因为我也一知半解)“协议+域名+端口”三者都相同,才同源,反着任意一个不同则跨域。同源策略限制的内容有(即同源才可以访问,跨域则不行):
    (1).Cookie,LocalStorage,IndexedDB等的存储内容
    (2).DOM节点。
    (3)ajax请求发送后,返回结果被浏览器拦截。
    三个允许跨域加载的标签:
     (1)<img src="xxxx">
       (2)<link href="xxxx">
        (3)<script src="xxx">

    注意:跨域并不会请求发不出去,请求能发送出去。服务端能收到请求并能正常返回结果,只是结果被浏览器拦截了。
    2.跨域解决方法

    1. jsonp
      利用script标签没有跨域限制的漏洞
      网页可以得到其他源动态产生的JSON数据。JSONP请求一定要对方的服务器做支持。只能get方法。
      实现步骤可以自行google,百度。简单说,声明一个回调函数传给跨域服务器,服务器返回数据时带上回调函数 并做特殊拼接:回调函数(‘要跨域获取的目标数据’),客户端声明这个回调函数的具体实现逻辑,当跨域服务器返回这个回调函数和目标数据的拼接时(即调用这个回调函数),则可以操作目标数据了,并获取。
      2.cors
      需要浏览器和后端同时支持.ie8和ie9需要通过XDomainRequest(啥东西,我不懂)来实现。
      服务器设置了Access-Control-Allow-Origin就可以开启CORS。该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问。
      前端分为简单请求和复杂请求
      简单请求:get,head,post同时Content-Type仅限text/plain,multipart/form-data,application/x-www-form-urlencoded
      复杂请求:不是简单的就是复杂的。复杂请求在正式通信前会增加一次HTTP查询请求即预检请求,请求方法为option来知道服务器是否允许跨域请求。
      3.postMessage
      postMessage是Html5 XMLHttpRequest level2中的API,是为数不多的跨域操作的window属性之一。作用:
      (1)页面和它打开的新窗口的数据传递。
      (2)多个窗口之间的消息传递
      (3)页面和嵌套iframe消息的传递
      (4)上面三个场景的跨域数据传递
      postMessage()方法允许来自不同源的脚本采用异步方式进行的有限通信,可以实现跨文本档,多窗口,跨域消息的传递
      实现:otherWindow.postMessage(‘messsage’,‘targetOrigin’,‘[transfer]’)
      message:是将要发送到其他window的数据。
      targetOrigin:通过窗口的origin属性来指定哪些窗口能接受到消息事件,其值可以是‘*’表示无限制或者一个url。(协议,主机,地址或端口必须和目标窗口一致)
      transfer:是一串和message同时发送的Tranferable对象,这些对象的所有权将转移给消息接受方,而发送方将步不再保有所有权。(不懂)
         // a.html
      <iframe src="b.html" frameborder="0" id="frame" onload="load()"></iframe//等它加载完触发一个事件
      //内嵌在a.html
      <script>
      function load() {
      let frame = document.getElementById('frame')
      frame.contentWindow.postMessage('我爱你', 'localhost:4000') //发送数据
      window.onmessage = function(e) { //接受返回数据
        console.log(e.data) //我不爱你
      }
      }
      </script>`
      `// b.html
      window.onmessage = function(e) {
      console.log(e.data) //我爱你
      e.source.postMessage('我不爱你', e.origin)
      }

      4.websocket(自己查)
      5.Node中间代理(两次跨域)
      原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循了。
      a.接受客户端请求。(代理服务器)
      b.将请求转发给服务器。
      c.拿到服务器响应数据(代理服务器)
      d.将数据转发给客户端
      6.nginx 反向代理
      7.window.name + iframe
      window.name 属性的独特之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

      // a.html(http://localhost:3000/b.html)
      <iframe src="c.html" frameborder="0" onload="load()" id="iframe"></iframe>
      <script>
      let first = true
      // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
      function load() {
      if(first){
      // 第1次onload(跨域页)成功后,切换到同域代理页面
      let iframe = document.getElementById('iframe');
      iframe.src = /b.html';
      first = false;
      }else{
      // 第2次onload(同域b.html页)成功后,读取同域window.name中数据
      console.log(iframe.contentWindow.name);
      }
      }
      </script>
      // c.html(http://localhost:4000/c.html)
      <script>
      window.name = '我不爱你'
      </script>

      8.location.hash + iframe
      实现原理: a.html 欲与 c.html 跨域相互通信,通过中间页 b.html 来实现。 三个页面,不同域之间利用 iframe 的 location.hash 传值,相同域之间直接 js 访问来通信。

具体实现步骤:一开始 a.html 给 c.html 传一个 hash 值,然后 c.html 收到 hash 值后,再把 hash 值传递给 b.html,最后 b.html 将结果放到 a.html 的 hash 值中。
同样的,a.html 和 b.html 是同域的

// a.html
  <iframe src="c.html#iloveyou"></iframe>
  <script>
    window.onhashchange = function () { //检测hash的变化
      console.log(location.hash);
    }
  </script>
 // b.html
  <script>
    window.parent.parent.location.hash = location.hash
    //b.html将结果放到a.html的hash值中,b.html可通过parent.parent访问a.html页面
  </script>
 // c.html
 console.log(location.hash);
  let iframe = document.createElement('iframe');
  iframe.src = 'b.html#idontloveyou';
  document.body.appendChild(iframe);

9.document.domain + iframe
该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。
只需要给页面添加 document.domain ='test.com' 表示二级域名都相同就可以实现跨域。

实现原理:两个页面都通过 js 强制设置 document.domain 为基础主域,就实现了同域。

// a.html
<body>
 helloa
  <iframe src="b.html" frameborder="0" onload="load()" id="frame"></iframe>
  <script>
    document.domain = 'zf1.cn'
    function load() {
      console.log(frame.contentWindow.a);
    }
  </script>
</body>
// b.html
<body>
   hellob
   <script>
     document.domain = 'zf1.cn
     var a = 100;
   </script>
</body>

总结
CORS 支持所有类型的 HTTP 请求,是跨域 HTTP 请求的根本解决方案
JSONP 只支持 GET 请求,JSONP 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据。
不管是 Node 中间件代理还是 nginx 反向代理,主要是通过同源策略对服务器不加限制。
日常工作中,用得比较多的跨域方案是 cors 和 nginx 反向代理

本作品采用《CC 协议》,转载必须注明作者和本文链接
一切皆自学
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 1

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!