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);

 

posted @ 2020-08-10 10:25  刘呆哗  阅读(212)  评论(0编辑  收藏  举报