美文网首页
跨域基础入门

跨域基础入门

作者: QQQQQCY | 来源:发表于2017-07-28 11:57 被阅读0次

    1. JSONP

    JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。

    它的基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。


    Example
    使用如下接口 https://api.asilu.com/ip/

    <!DOCTYPE html>
    <body>
     <script>
    //  设置回调函数
      function foo(data){
        console.log(data)
      }
      </script>
      <script src='https://api.asilu.com/ip?callback=foo'></script>
    </body>
    
    //  输出
    {
        "ip": "118.250.83.107",
        "dz": "湖南省长沙市",
        "wl": "电信"
    }
    

    mock测试

    <!DOCTYPE html>
    <body>
     <script>
      function foo(e){
        console.log(e)
      }
      </script>
      <script src='http://localhost:8080/test?callback=foo'>
      </script>
    </body>
    
    // 后端mock
    router.get('/test',function(req,res){
        var cb = req.query.callback
        var mockData = {
            a1:'abc',
            a2:'123',
            a3:'hello'
        }
        res.send(cb + '(' + JSON.stringify(mockData) +')')
    })
    
    //  输出
    Object {a1: "abc", a2: "123", a3: "hello"}
    

    script封装写法

    function addScriptTag(src) {
      var script = document.createElement('script');
      script.setAttribute("type","text/javascript"); 
      script.src = src; 
      document.body.appendChild(script);
    }
    
    window.onload = function () { 
      addScriptTag('http://example.com/ip?callback=foo');
    }
    
    function foo(data) { 
      console.log('Your public IP address is: ' + data.ip);
    };
    

    2. CORS

    CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

    整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

    因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。


    Example
    使用如下接口 http://api.jirengu.com/city.php

    <!DOCTYPE html>
    <body>
      <script>
        var xhr = new XMLHttpRequest()
        xhr.onreadystatechange = function(){
          if (xhr.readyState === 4)
            if (xhr.status === 200){
                console.log(xhr.response)
            }
        }
        xhr.open('get','http://api.jirengu.com/city.php')
        xhr.send()
      </script>
    </body>
    
    //  输出
    长沙市
    

    mock测试

    <!DOCTYPE html>
    <body>
      <script>
        var xhr = new XMLHttpRequest()
        xhr.onreadystatechange = function(){
          if (xhr.readyState === 4)
            if (xhr.status === 200 || xhr.status === 304){
                console.log(xhr.response)
            }
        } 
        xhr.open('get','http://localhost:8080/test2')
        xhr.responseType = 'json'
        xhr.send()
      </script>
    </body>
    
    // 后端
    router.get('/test2',function(req,res){
        var cb = req.query.callback
        var mockData = {
            a1:'abc',
            a2:'123',
            a3:'hello'
        }
        console.log(res.header)
        res.header('Access-Control-Allow-Origin','*')
        res.send(mockData)
    })
    
    //  输出
    Object {a1: "abc", a2: "123", a3: "hello"}
    

    3. postMessage

    效果预览

    HTML5引入了一个全新的API:跨文档通信 API(Cross-document messaging)。

    这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。

    举例来说,父窗口aaa.com向子窗口bbb.com发消息,调用postMessage方法就可以了。


    Example

    //  父窗口代码  
    <!DOCTYPE html>
    <body>
      <button id='oaw'>open a window</button>
      <button id='oai'>open a iframe</button>
      <button id='cc'>change color</button>
      <div>
      </div>
      <script>
          var url = 'http://localhost:8080/index2.html'
          var oaw = document.querySelector('#oaw')
          var oai = document.querySelector('#oai')
          var cc = document.querySelector('#cc')
          var iframe = document.createElement('iframe')
          var popuo
          iframe.setAttribute('src',url)
    
          oaw.addEventListener('click',function(){
              popuo = window.open(url,'title')
          })  //  打开一个新窗口
    
          oai.addEventListener('click',function(){
              document.querySelector('div').appendChild(iframe)
          })  //  打开一个iframe
    
          cc.addEventListener('click',function(e){
            function random(min,max){
                 return Math.floor(min+(max-min)*Math.random());
          }   //  点击按钮时候改变子窗口颜色
            var color = '#'+random(100,999)
    
            if (popuo) popuo.postMessage(color,url)
            if (iframe.contentWindow) iframe.contentWindow.postMessage(color,url)
          })
    
          window.addEventListener('message',function(e){     //   接收子窗口回传的data
            document.body.style.background = e.data
          })
      </script>
    </body>
    
    //  子窗口代码  
    <!DOCTYPE html>
    <style>
        div {
            background: yellow;
            width: 100vw;
            height: 100vh;
        }
    </style>
    <body>
        <div></div>
        <script>
            window.addEventListener('message',function(e){  //  接收父窗口发过来的data
                document.querySelector('div').style.background = e.data
                e.source.postMessage(e.data,'*')    //  接收到的data发往父窗口
            })
        </script>
    </body>
    

    4. 片段识别符

    片段标识符(fragment identifier)指的是,URL的#号后面的部分,比如http://example.com/x.html#fragment#fragment。如果只是改变片段标识符,页面不会重新刷新。

    父窗口可以把信息,写入子窗口的片段标识符。

    var src = originURL + '#' + data;
    document.getElementById('myIFrame').src = src;
    

    子窗口通过监听hashchange事件得到通知。

    window.onhashchange = checkMessage;
    
    function checkMessage() {
      var message = window.location.hash;
      // ...
    }r
    

    同样的,子窗口也可以改变父窗口的片段标识符。

    parent.location.href= target + “#” + hash;
    

    example

    //  父页面  
    <!DOCTYPE html>
    <body> 
      <button id='oai'>open a iframe</button>
      <div>
      </div>
      <button id='curl'>change color</button>
      <script>
          var curl = document.querySelector('#curl')
          var iframe = document.createElement('iframe')
          var url = 'http://localhost:8080/index2.html'
          iframe.setAttribute('src',url)
    
    
          oai.addEventListener('click',function(){
              document.querySelector('div').appendChild(iframe)
          })  //  打开一个iframe
    
          curl.addEventListener('click',function(e){
            function random(min,max){
                 return Math.floor(min+(max-min)*Math.random());
          }   //  点击按钮时候改变子窗口颜色
            var color = '#'+random(100,999)
            iframe.src = url + color
          })
      </script>
    </body>
    
    //   子页面
    <!DOCTYPE html>
    <style>
        div {
            background: yellow;
            width: 100vw;
            height: 100vh;
        }
    </style>
    <body>
        <div></div>
        <script>
            window.onhashchange = checkMessage
            function checkMessage(e){
                document.querySelector('div').style.background = window.location.hash
            }
        </script>
    </body>
    

    两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值


    参考
    阮一峰 - 同源政策
    林东洲 - 关于跨域

    相关文章

      网友评论

          本文标题:跨域基础入门

          本文链接:https://www.haomeiwen.com/subject/tovnkxtx.html