美文网首页
几种跨域方式的演示

几种跨域方式的演示

作者: zh_yang | 来源:发表于2017-09-15 11:27 被阅读0次

    一、JSONP

    JSONP原理

    • 利用<script>标签没有跨域限制来达到与第三方通讯的目的。
    • 当需要通讯时,本站脚本创建一个<script>元素,地址指向第三方的API网址,形如: <script src="http://www.example.net/api?callback=appendHTML"></script> 并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。
      如上边的地址约定了回调函数为appendHTML( ),当第三方服务器检测到callback=appendHTML( ),会将数据打包到函数里返回:appendHTML(...数据...),使用方已经生命了appendHTML(),函数,所以返回的数据会执行。
    • 第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),形如: callback({"name":"hax","gender":"Male"}) 这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。

    无后端服务器演示JSONP

    • 以Windows为例,更改houts文件,地址为C:\Windows\System32\drivers\etc\housts
      添加如下内容:
        127.0.0.1   aa.zhihaoy.com
        127.0.0.1   bb.zhihaoy.com
    

    这样我们在127.0.0.1布置了两个域名

    • 然后创建a.html:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>aaa</title>
    </head>
    <body>
    <p id="aaa">aaa</p>
        <script type="text/javascript">
            function xxx (data) {
                var p = document.getElementById('aaa')
                p.innerText=('姓名:'+data.name+'\n'+'年龄:'+data.age)
            }
        </script>
        <script type="text/javascript" src="http://bb.zhihaoy.com/test.txt"></script>
    </body>
    </html>
    
    • 创建test.txt(不一定非是js格式,能够拿到数据就行,都会按js语法执行)
    xxx({name:'jrengu',age:3})
    
    • 开启本地服务器:(这里用的是80端口)
    测试01.png
    注释掉模拟执行请求的script标签,在浏览器地址栏输入http://aa.zhihaoy.com/a.html
    页面显示: 测试02.png
    还原模拟执行请求的script标签,刷新页面(请求的地址是:http://bb.zhihaoy.com/test.txt 测试03.png 测试04.png

    这样就跨域获得并执行了数据,关键在于双方约定的xxx( )函数,否则拿到数据也不执行。

    server mock 演示 JSONP

    • 创建a.html,为了和上边区分做了更改:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>aaa</title>
    </head>
    <body>
    <p id="aaa">aaa</p>
        <script type="text/javascript">
            function getWeather (data) {
                var p = document.getElementById('aaa')
                p.innerText=('杭州:'+data.weather)
            }
        </script>
        <script type="text/javascript" src="http://127.0.0.1:8080/getWea?city=hangzhou&callBack=getWeather"></script>
        //获取杭州天气
    </body>
    </html>
    
    • mock第三方后端数据
    测试05.png
    • 在命令行启动本地服务器:
    测试06.png 测试07.png 测试08.png

    尝试封装JSOP

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>aaa</title>
    </head>
    <body>
        <p id="aaa">aaa</p>
        <script type="text/javascript">
            function getWeather(data){
                var p = document.getElementById('aaa')
                p.innerText=('杭州:'+data.weather)
            }
            function jsonP (url,callBack,data) {
                var script = document.createElement('script')
                script.src = url+'?'+data+'&callBack='+callBack
                document.head.appendChild(script)
                document.head.removeChild(script)
            }
            jsonP ("http://127.0.0.1:8080/getWea",'getWeather','city=hangzhou')
        </script>
    </body>
    </html>
    

    测试后效果一样

    二、CORS

    原理:

    在HTTP请求里添加特殊的头,允许服务器指定特定的域名可以跨域访问。

    server mock 演示 CORS

    • a.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>aaa</title>
    </head>
    <body>
        <input id="inta" type="button" value="获取天气">
        <p>我是AAA</p>
        <script type="text/javascript" src="myAJAX.js"></script>
        <script type="text/javascript">
            var btna = document.getElementById('inta')
            var p = document.getElementsByTagName('p')[0]
            btna.onclick = function () {
                myAJAX('GET','http://127.0.0.1:8080/getWea?city=hangzhou',function(data){
                    p.innerText = '杭州:' + JSON.parse(data).weather
                })
            }
        </script>
    </body>
    </html>
    
    • router.js
    /**
     * 当 http://localhost:8080/getFriends 的GET请求到来时被下面匹配到进行处理
     * 通过req.query获取请求的参数对象 
     * 通过 req.send发送响应
     */
    router.get('/getWea', function(req, res) { 
      var city = req.query.city // 通过 req.query获取请求参数
      var data
        //根据请求参数mock数据
      switch (city) {
        case 'hangzhou':
          data = {
            weather: "多云"
          }
          break
        case 'shanghai':
          data = {
            weather: "中雨"
          }
          break;
        default:
          data = {
            weather: "无信息"
          }
      }
      res.send(data)
    })
    
    • 默认情况不能跨域使用AJAX,在80端口打开a.html,去请求8080端口,得到:


      测试09.png
    • 设置 header 可以处理跨域请求
      设置后的router.js
    router.get('/getWea', function(req, res) {
      res.header('Access-Control-Allow-Origin', 'http://aa.zhihaoy.com')
      //或者res.header('Access-Control-Allow-Origin', '*');
      //设置 header 
      var city = req.query.city // 通过 req.query获取请求参数
      var data
        //根据请求参数mock数据
      switch (city) {
        case 'hangzhou':
          data = {
            weather: "多云"
          }
          break
        case 'shanghai':
          data = {
            weather: "中雨"
          }
          break;
        default:
          data = {
            weather: "无信息"
          }
      }
      res.send(data)
    })
    

    刷新a.html得到:


    测试10.png 测试11.png

    三、降域document.domain

    原理:

    操作iframe,这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域同时为两个域设置document.domain= xxx.com

    • a.html里有一个iframe(两者域名不同)
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>aaa</title>
    </head>
    <body>
        <input id="inta" type="text" placeholder="aaa">
        <p>我是AAA</p>
        <iframe src="http://bb.zhihaoy.com/b.html" width="300px" height="200px" style="border: 1px dotted"></iframe>
        <script type="text/javascript">
            //document.domain= 'zhihaoy.com'   默认不降域
            var btna = document.getElementById('inta')
            btna.oninput = function(){
                window.frames[0].document.getElementById('intb').value = this.value
            }
        </script>
    </body>
    </html>
    
    • b.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>bbb</title>
    </head>
    <body>
        <input id="intb" type="text" placeholder="bbb">
        <p>我是BBB</p>
        <script type="text/javascript">
            //document.domain= 'zhihaoy.com'   默认不降域
            var btnb = document.getElementById('intb')
            btnb.oninput = function(){
                window.parent.document.getElementById('inta').value = this.value
            }
        </script>
    </body>
    </html>
    
    • 不降域的情况下载a.html操作b.html会报错


      测试12.png
    • 降域后则正常运行
    测试13.png

    postMessage

    原理

    postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

    postMessage(data,origin)方法接受两个参数

    1.data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。

    2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

    演示postMessage

    • a.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>aaa</title>
    </head>
    <body>
        <input id="inta" type="text" placeholder="aaa">
        <p>我是AAA</p>
        <iframe src="http://bb.zhihaoy.com/b.html" width="300px" height="200px" style="border: 1px dotted"></iframe>
        <script type="text/javascript">
            var btna = document.getElementById('inta')
            btna.oninput = function(){
                window.frames[0].postMessage(this.value,'*')
            }
            window.addEventListener('message',function(e){
                btna.value.e.data
            })
        </script>
    </body>
    </html>
    
    • b.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>bbb</title>
    </head>
    <body>
        <input id="intb" type="text" placeholder="bbb">
        <p>我是BBB</p>
        <script type="text/javascript">
            var btnb = document.getElementById('intb')
            btnb.oninput = function(){
                window.parent.postMessage(this.value,'*')
            }
            window.addEventListener('message',function(e){
                btnb.value=e.data
            })
        </script>
    </body>
    </html>
    
    • a.html和b.html域名不同,但是可以互相传递数据
    测试14.png

    相关文章

      网友评论

          本文标题:几种跨域方式的演示

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