zoukankan      html  css  js  c++  java
  • jsonp原理

    jsonp原理

     

     

    推荐技术站:

    https://segmentfault.com/a/1190000015597029 

    Content-Type和Accept的关系:

    https://www.jianshu.com/p/2283ed2751d9

     

     

    跨域【jsonp】

    跨域请求的概念

    Ajax跨域问题

    跨域的解决方案

    跨域实现原理

    json与jsonp

    使用jsonp接口的两个步骤

    jQuery的jsonp

    jsonp实现原理

     

     

     

     

    跨域请求的概念

    JavaScript出于安全考虑,不允许跨域调用其他页面的对象。

     

    仅在同源条件下可以访问。

     

    Ajax跨域问题

    --出于安全考虑,浏览器不允许ajax跨域获取数据。

    --可以通过script的src加载js的方式传递数据。

    以函数参数的形式传递数据:

    fn({"a":1,"b":2});

     

     

     

    跨域的解决方案

    1.iframe

    2.jsonp

    3.服务器端解决【在响应头上(header)加上:Access-Control-Allow-Orign:允许的网址,如果写*则代表所有】

     

     

     

    跨域实现原理

    1.Script的src方式加载js文件

    2.加载的js文件内进行函数调用

    3.数据以函数参数的形式传递

    4.回调函数中获取参数数据

    注意:是js中去主动创建一个script标签,然后src属性里写请求的地址。在一般情况下,服务器会根据Accept【是请求头中的一个字段】的值,来决定返回的数据的类型,并设置Content-Type【是响应头中的一个字段】,通常Content-Type的值和Accept的第一个值相等

     

     

     

    json与jsonp

    json:是一种基于文本的交换格式【不支持跨域】

    jsonp:是一种非官方跨域数据交互协,是一种解决跨域请求的方案。jsonp是json with paramter的简称,即:json通过参数的形式给到你。

     

     

     

    使用jsonp接口的两个步骤

    1.定义一个函数,用于解析jsonp接口传递回来的数据

    2.调用一下jsonp接口:调用方式-》创建一个script标签-》url链接中&_jsonp=函数名-》将script追加到页面【script执行的结果就是一个函数,其实是将函数调用追加到页面】

     

     

     

    jQuery的jsonp

    $.ajax({
                type:"get",
                url:"./jquery_jsonp.php",
                dataType:"jsonp",
                   jsonpCallback:"callback"
                success:function(json){
                    console.log(json);
                },
                error:function(data){
                    console.log(data);
                    console.log(456);
                }
            });
    callback(data);

    jsonp实现原理

    <!DOCTYPE html>
    <html lang="en">
    <head>
       <meta charset="UTF-8">
       <title>Document</title>
       <script>
       // 必须放在全局作用域内,不能放在自执行函数里
          function abc(data) {
             document.write(data);
          }
       </script>
       
       <!-- 下面script标签的执行结果即:abc(["a","b","c"]) -->
       <script src="./jsonp.php?_jsonp=abc"></script>
    </head>
    <body>
       
    </body>
    </html>
    <?php
    $_jsonp = $_GET['_jsonp'];
    $arr = array("a","b","c");
    echo $_jsonp.'('.json_encode($arr).')';
    ?>

    通过一个script标签发送请求,返回的是一个js脚本。也就是说上面的请求服务器返回的js脚本是:

    abc(['a','b','c'])

    这个脚本被请求到后立即被执行,当执行到abc函数时,就会在全局作用域里去找一个abc的方法,找到了就去执行。

    支持跨域的还有:

    img、iframe、link、script都可以做跨域,他们每一个在js中都是一个对象。

    <!--统计链接,支持跨域但是无法实现获取服务器端返回的数据-->
    <img src="" alt="">
    <!--支持跨域,可以接收服务器端数据,但是过程复杂-->
    <iframe src="" frameborder="0"></iframe>
    <!--支持跨域,会在css处理阶段报错-->
    <link rel="stylesheet" href="">
    <!--最方便的使用跨域的方式,要求跨域函数必须是全局的,不能放在自执行函数里-->
    <script src=""></script>

    自己手写一个jsonp技术【有严重bug】:

    // jsonpSev.js
    'use strict';
    
    /*
        自己实现一个jsonp的服务,仿照创建script的方式
            1.创建回调函数,挂载到全局
            2.拼接jsonp格式的url
            3.创建script,并添加到页面
    */
    (function (window, document) {
        /*
            @url:请求地址 http://api.douban.com/v2/movie/top250
            @data:请求参数 {start:0,count:25}
         */
        var jsonpfun = function (url, data, callback) {
    
            /*1.创建回调函数,挂载到全局*/
            var cnName = 'cb_jsonp_' + (+new Date());
            window[cnName] = callback;
    
    
            /*2.拼接jsonp格式的url*/
            var suffix = url.indexOf('?') != -1 ? 'callback=' + cnName : '?callback=' + cnName;
            for (var k in data) {
                suffix += '&' + k + '=' + data[k];
            }
    
            /*3.创建script,并添加到页面*/
            var script = document.createElement('script');
            script.src = url + suffix;
            document.querySelector('body').appendChild(script);
        }
    })(window, document);

    上面代码有一个问题:就是每次点击下一页都会创建一个script,而这个script在加载过后就不在起作用,这就造成了页面中大量无用的script标签。改进写法:

    'use strict';
    
    /*
       自己封装angular的jsonp,
       原由:豆瓣不支持angular封装的jsonp格式,由于angular封装的
          以不污染全局为思想,将jsonp的回调函数封装在angular.callback
          中,而且回调函数命名为angular.callback._0(),豆瓣不支持
    */
    (function (angular) {
       var $jsonp = angular.module('jsonpSev', []);
       $jsonp.service('$jsonp', ['$window', '$document', function ($window, $document) {
          /*
          * 创建自己的jsonp
          *  1.创建callback函数,挂载到全局
          *  2.拼接url => url?name=xx&age=xx
          *  3.创建script,添加到页面
          * */
          this.jsonp = function (url, params, callback) {
             // 1.创建callback函数,挂载到全局[放在后面挂载了]
             var cbName = 'jsonp_callback_' + (+new Date());
    
             // 2.拼接url
             var suffix = url.indexOf('?') != -1 ? 'callback=' + cbName : '?callback=' + cbName;
             for (let d in params) {
                suffix += '&' + d + '=' + params[d];
             }
    
             // 3.创建script,添加到页面
             var script = $document[0].createElement('script');
             script.src = url + suffix;
    
             // 把挂载到全局放在创建script后面,因为马上我们要移除
             // 这个script[当这个script请求的脚本呗执行后,这个script不在有用]
             $window[cbName] = function (data) {
                callback(data);
                $document[0].querySelector('body').removeChild(script);
             };
    
             $document[0].querySelector('body').appendChild(script);
          }
       }])
    })(angular);

     

    前进时,请别遗忘了身后的脚印。
  • 相关阅读:
    基本排序算法分析
    Linux内核浅谈
    Linux内核浅谈
    Linux内核浅谈
    淘宝架构技术的演变
    淘宝架构技术的演变
    淘宝架构技术的演变
    中间件小结
    中间件小结
    中间件小结
  • 原文地址:https://www.cnblogs.com/liudaihuablogs/p/13468282.html
Copyright © 2011-2022 走看看