jQuery实现jsonp

作者: microkof | 来源:发表于2017-04-01 15:44 被阅读918次

    jsonp本身是专为跨域而诞生的。早期开发者面对跨域没什么好办法,突然有人想到,既然引入js文件是不受跨域限制的,可以随意跨域引入,那么,动态引入一个带有你想要的数据的js文件,不就实现了跨域了么?由此jsonp技术诞生。

    注意,jsonp技术跟ajax没有任何关系,只不过jQuery带了一个坏的头,让人们误以为jsonp跟ajax有关。

    原理

    jsonp的原理简单说就是:

    第一步,你的HTML中应当提前准备一个函数,比如叫ooo,大致如下,它只干一个事情,就是把json字符串转换为json对象:

    function ooo(data) {
      return JSON.parse(data);
    }
    

    第二步,你在你的HTML中用js拼接字符串的方式拼接一个类似于<script src="http://外域.com/xxx.php?callback=ooo"></script>的script元素。这个http://外域.com/xxx.php?callback=ooo的内容如下:

    ooo({"name": "张学友"})
    

    然后你需要操作DOM,把上面的<script src="http://外域.com/xxx.php?callback=ooo"></script>插入到DOM中,这样浏览器就会把这个地址当做js文件载入,然后试图执行里面的js内容。

    既然这个文件被当做js来插入DOM,那么里面所有代码都是js代码,这个ooo({"name": "张学友"})就是js代码,浏览器会找有没有一个叫ooo的函数,显然有,我们刚才不是定义了一个ooo函数么?所以浏览器找到了这个函数,之后就执行这函数。

    最后,我们就得到了一个json对象,而这个对象就是来自于外域服务器。由此,跨域达成。

    没错吧,从头到尾并没有ajax什么事。

    可以看出,本域跟外域沟通的桥梁,是外域的一个php文件,接头暗号就是路径里的参数callback=ooo。也就是说,php文件要做的事情应该是:

    获取callback参数的值,然后拼接一个字符串ooo({"name": "张学友"}),其中ooo来自callback参数的值,{"name": "张学友"}是从sql中查询到的结果。

    用jQuery实现jsonp的好处

    然后说说jQuery的实现。jq为了让使用者更省心,当然是做了很多自动化的工作,下面都可以一一看到。主要是:

    1、你不用自己写类似这样的函数,因为jQuery已经帮你写了:

    function ooo(data) {
      return JSON.parse(data);
    }
    

    2、你不用思考函数名用啥名,因为jQ会帮你瞎编一个函数名,通常长相是jQuery32108394227022163139_1498134481374一大串。

    jQuery中怎么实现jsonp

    通常三种办法:

    第一种,$.ajax()方法

    当引入http://外域.com/xxx.php?callback=ooo,php端必须让这个地址能打印出ooo({"name": "张学友"})这样的内容,函数名ooo必须跟下面的jsonpCallback的值一致。json内容可以任意。

    JS:

    $.ajax({
        url:'http://外域.com/xxx.php',
        dataType:"jsonp",
        jsonp: "callback",
        jsonpCallback:"ooo",
        success:function(data){
            console.log(data);
        }
    });
    

    这个例子里面,明确指定了jsonp: "callback"以及jsonpCallback:"ooo"。我们分别说一下:

    jsonp: "callback"是设置路径里的参数名。你这里写callback,那么jQuery发送请求的时候路径里就用callback=

    jsonpCallback:"ooo"是设置函数名。你这里写ooo,那么php必须返回ooo为函数名的内容。

    这两者都可以省略,jsonp的值省略的话,缺省是callback。jsonpCallback的值省略的话,缺省是类似jsonp3731491014413739这样的'jsonp'加16位随机数。两者都省略的话,jQuery就会在路径后面接一个callback=jsonp3731491014413739这样的参数,那么,你的php就必须返回jsonp3731491014413739({"name": "张学友"})这样的字符串。说白了,你如果js端想少写几个字,打算省掉这两个参数,那么php端就多写一些代码,需要先获取$_GET['callback']的值,根据值拼接字符串,因此你就不可能写死函数名。

    最佳实践是省掉这两个参数,不过你的php端就要对参数值做安全措施。

    第二种,$.get()方法(作者推荐)

    $.get()方法的基本用法是同域名抓数据,是真正的ajax原理。而高级用法就是抓jsonp数据。写法是:

    $.get('http://外域.com/xxx.php', {各种数据}, function(data) {
        console.log(data);
    }, 'jsonp');
    

    没有指定末尾的'jsonp'参数的时候,jQuery认为你想同域抓数据,会用xhr方法请求;只有加了参数,才认为你想抓jsonp数据。这一切由jQuery自动判断。

    这个写法其实就是上面ajax写法的简化版,而且肯定设不了jsonp和jsonpCallback,所以你的php必须用类似echo $_GET['callback'].'({"name":"张学友"})';这样的写法。假如你的路径中本来就有callback参数,而且这个callback是干别的用的,那么你就没法用$.get()方法。因为你真正的请求路径会是:http://外域/xxx.php?callback=12345678&callback=jQuery321040155744415047234_1498133674752&_=1498133674753,看到了吧,两个callback参数,php只会认后一个,忽略前一个。

    第三种:$.getJSON()方法

    $.getJSON()方法跟$.get()方法类似,区别在于:

    1、$.getJSON()的最后一个参数不用写,而$.get()方法的最后一个参数必须是'jsonp'。

    2、$.getJSON()虽然省掉了最后一个参数,但这时候,你需要在路径中带上callback=?或者abc=?这样的字眼,这样jQuery会自动判断,既然你带上了参数,而且参数值是问号,那么jQuery就认为你想搞jsonp勾当,如果你不加任何参数,或者参数值不是问号,那么jQuery就认为你不想搞jsonp勾当,那么这时候$.getJSON()方法就全等于$.get(...,..., 'json')方法。

    同样的,你如果用callback=?,那么你php里应该是echo $_GET['callback'].'({"a": "张学友"})';,如果你用abc=?,那么你php里得是echo $_GET['abc'].'({"a": "张学友"})';

    $.getJSON('http://外域/xxx.php?abc=?', {各种数据}, function(data) {
        console.log(data);
    });
    

    结论

    要让我选最好用的一个,我选$.get()方法,因为$.get()方法的最后一个参数'jsonp'能显式声明这个请求是jsonp请求,再一个,$.getJSON()方法的url要加上callback=?这种字眼,显得繁琐。

    $.ajax()方法不到必要时不要用,必须用的时候当然一定要用。

    相关文章

      网友评论

        本文标题:jQuery实现jsonp

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