前端跨域解决方案

什么是跨域

浏览器从一个域名的网页去请求另外一个域名的资源时,域名、端口、协议任一不一样,都是跨域,它是由浏览器的同源策略形成的,是浏览器对JavaScript实施的安全限制。javascript

1 . 经过document.domain跨域

  • 概念php

    该属性是一个只读的字符串,包含了载入当前文档的 web 服务器的主机名。html

  • 特色html5

    只有在一级域名相同的状况下才能够实现跨域。java

  • 代码web

/**
 * 父域:http://b.com/b.com.html内容
 */
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script> document.domain = 'b.com'; var ifr = document.createElement('iframe'); ifr.src = 'http://a.b.com/a.b.com.html'; ifr.style.display = 'none'; document.body.appendChild(ifr); ifr.onload = function(){ var doc = ifr.contentDocument || ifr.contentWindow.document; // 这里操做DOM var oUl = doc.getElementById('ul1'); alert(oUl.innerHTML); ifr.onload = null; } </script>
</body>
</html>

/**
 * 子域:http://a.b.com/a.b.com.html
 */
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script> document.domain = 'b.com'; </script>
<ul id="ul">我是子域a.b.com中的UL</ul>
</body>
</html>
复制代码

2 . 经过HTML5的postMessage方法跨域

  • 概念算法

    是html5引入的API能够更方便、有效、安全的解决跨域问题。postMessage()方法容许来自不一样源的脚本采用异步方式进行有限的通讯,能够实现跨文本档、多窗口、跨域消息传递。json

  • 语法后端

    /** * [description] * @param {[string]} message 其余窗口的一个引用,好比iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。 * @param {[string]} targetOrigin 将要发送到其余 window的数据。它将会被结构化克隆算法序列化。这意味着你能够不受什么限制的将数据对象安全的传送给目标窗口而无需本身序列化 * @param {[string]} targetOrigin */
      otherWindow.postMessage( message, targetOrigin, [ transfer ] )
    复制代码
  • 代码api

    /** * A页面经过postMessage方法发送消息: */
     window.onload = function() {  
         var ifr = document.getElementById('ifr');  
         var targetOrigin = "http://www.google.com";  
         ifr.contentWindow.postMessage('hello world!', targetOrigin);  
     }
     
     /** * B页面经过message事件监听并接受消息: * 同理也能够B页面发送消息而后A页面监听并接受消息。 */
     var onmessage = function (event) {  
         var data = event.data;//消息 
         var origin = event.origin;//消息来源地址 
         var source = event.source;//源Window对象 
         if(origin=="http://www.baidu.com"){  
             console.log(data);//hello world! 
         }  
     } 
     if (typeof window.addEventListener != 'undefined') {  
         window.addEventListener('message', onmessage, false);  
     } else if (typeof window.attachEvent != 'undefined') {  
         //for ie 
         window.attachEvent('onmessage', onmessage);  
     }
    复制代码

3. 经过CORS跨域

  • 概念

    CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想就是使用自定义的HTTP头部(Access-Control-Allow-Origin)让浏览器与服务器进行沟通,从而决定请求或响应是应该成功仍是失败。目前,全部浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通讯过程,都是浏览器自动完成,不须要用户参与。对于开发者来讲,CORS通讯与同源的AJAX通讯没有差异,代码彻底同样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感受。所以,实现CORS通讯的关键是服务器。只要服务器实现了CORS接口,就能够跨源通讯。

  • 兼容状况

    在标准浏览器下XMLHttpRequst已是最新版本了,它不推荐使用onreadystatechange这个事件来监听,推荐使用onload,另外IE若是想要实现跨域则须要使用XDomainRequest对象去实现

  • XMLHttpRequst特色

    • 能够访问对象的status和statusText属性并且还支持同步请求。
    • 不能使用setReruestHeader设置自定义头部。
    • 不能发送和接受cookie
    • 调用getAllResponseHeaders()方法总会返回空字符串
  • XDomainReques特色

    • cookie不会随请求发送,也不会随响应返回。
    • 只能设置请求头部中信息中的Content-Type字段。
    • 不能访问响应头部信息。
    • 只支持GET和POST请求
    • XDomainReques对象的open()只支持两个参数请求的类型和URL,全部的XDR默认都是异步请求
  • 代码

    /** * XDomainReques * 后端须要设置头部信息Access-Control-Allow-Origin:https://www.baidu.com */
      let xdr = new XDomainReques()
      xdr.onload = function(){
          alert(xdr.resposeText)
      }
      xdr.open('get', 'https://www.baidu.com/page')
      xdr.contentType = 'application/x-www-form-urlencoded'
      xdr.send()
      
    /** * XMLHttpRequst * 后端须要设置头部信息Access-Control-Allow-Origin:https://www.baidu.com */
      let xhr = new XMLHttpRequest()
      xhr.onreadystatechange = function() {
          if (xhr.readyState == 4) {
              if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
                  alert(xhr.responseText);
              }
          }
      }
      xhr.open('get', 'https://www.baidu.com/page', true)
      xhr.send(null)
    复制代码

4. 经过JSONP跨域

  • 原理

    经过script标签引入的js是不受同源策略的限制的。动态的建立过script标签引入一个js或者是一个其余后缀形式(如php,jsp等)的文件,此文件返回一个js函数的调用,来实现跨域。

  • 代码

    // 简单demo
    <!DOCTYPE html>
        <html>
        <head>
            <meta charset="utf-8">
            <title></title>
            <script> function show(json) { alert(json.s) } </script>
            <script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=acc&cb=show" charset="utf-8"> </script>
        </head>
    </html>
    复制代码
    /** * jsonp 原声音封装 */ 
    function jsonp(obj) {
        //写入url地址中的函数名称,动态建立
        var callbackName = 'jsonp_callback_' + Date.now() + Math.random().toString().substr(2, 5);
        
        //建立一个script标签
        var scriptObj = document.createElement("script");
            
        obj.parames = obj.parames || '';
        if (typeof obj.parames == 'object') {
            var arr = new Array();
            for (var key in obj.parames) {
                arr.push(key + '=' + obj.parames[key])
            }
            obj.parames = arr.join('&');
        }
        //设置标签的请求路径
        //像这样:http://localhost:3000/api?callback=jsonp_callback_153498520409635392&id=1
        scriptObj.src = obj.url + '?' + 'callback=' + callbackName + '&' + obj.parames;
    
        //将建立好的带请求的script标签添加到html的body中
        document.body.appendChild(scriptObj);
    
        //这里必须这样写window[callbackName];
        //若是写window.callbackName会报错没有定义
        window[callbackName] = function (res) {
            obj.success(res);
            //删除的时候能够这样写
            //因为请求一次会建立一个script标签和一个函数,因此每次获取到结果后就删除
            delete window.callbackName;
            document.body.removeChild(scriptObj);
        }
    }
    
    /** * 调用 */
    jsonp({
        //请求地址
        url:'http://localhost:3000/api',
        //请求参数,对象
        parames:{
            id: 1
        },
        //成功回调
        success:function (res) {
            console.log(res)
        }
    })
    复制代码
相关文章
相关标签/搜索