如果要在jq里进行跨域,一般来说只有使用jsonp,另一种方式则是进行中间层欺骗,也就是所谓的反代。

这里我们主要讲讲json是怎么回事

基本json

实现jsonp全部都是使用带有src标签的元素,一般默认使用script元素,在src链接地址中,在地址后面加上?name=value&callbakc=hd;其中name=value是传值,而callbakc=hd则是回调,在本地js全局作用域下创建一个名为hd的函数。

var script = document.createElement("script");
script.src = "xxxx?callback=hd";
document.getElementsByTagName('head')[0].appendChild(script);


//回调函数
function hd(data) {
  console.log(data);
}

//或者使用变量名赋值
var hd = function(data) {
  console.log(data);
}

重点就是这个回调函数,hd带有一个参数,这个参数就是服务器通过动态创建并返回给你的,因为script元素在加载完毕后执行内部代码,而内部等于hd(data),就是一个执行hd的代码段,于是你之前创建的hd函数成为了回调函数并运行。

注意:因为json的文件格式js是支持的,所以回调函数执行后并不会提示警告,而如果服务器动态创建给你的是html类型的文件,那么虽然能通过script元素加载运行,但是会提示你(即使其 MIME 类型(“text/html”)不是有效的 JavaScript MIME 类型,仍已加载来自xxx的脚本)

这里就有人想了,那jq不是有一个dataType的属性吗,可以告诉服务器我期望返回的文件类型,然而这种想法是不对的,我们下面来讲到他真正的作用。

jq的jsonp

$.ajax({
     url:'xxx',
     type : 'GET',
     data:{
          key : "xxx",
          com : "xxx",
          no : "xx"
      },
    dataType : 'jsonp',
    success:function(data){
          console.log(data);
      }
})

这是一个标准的jq的jsonp格式,这里我们没有给url加上callback但是依旧会成功,原因就是我们声明了期望返回的格式为‘jsonp’,然而实际上并没有这种格式,jsonp只是一个名称,一般来说他应该是一个js文件,或者是一个json格式的文件,而我们设置jsonp实际上是给jq用于判断该用什么方式来获取。

那么jq会先创建一个script元素,其src=xxx?key=xxx&com=xxx&no=xxx&callback=?,然后插入head中,加载完毕运行后再remove()删除;

为此我还特意去截了下图:

这里我们可以看到callback=?变成了callback=JQueryxxxxx跟了一大串字符,这个实际上就是jq自己随机创建的回调函数名,在没有指定回调函数名的情况下,JQueryxxxxx == success 里的函数,如果指定了,那就等于指定的函数。

自定义jsonp回调函数

比如我指定他的回调函数要是qiaolima,那么使用jsonpCallback属性

$.ajax({
     url:'xxx',
     type : 'GET',
     data:{
          key : "xxx",
          com : "xxx",
          no : "xx"
      },
    dataType : 'jsonp',
    success:function(data){
          console.log(data);
      },
    jsonpCallback : 'qiaolima'
})

//注意这个函数必须为全局函数,不能写在
//$(document).ready(function(){//不能写在这里}),
//而是要在外面
function qiaolima(data) {
  alert(data)
}

这里再讲一下callback=?的效果,jq会自动判断,将?替换为函数,如果没有指定回调函数名,会自己随机生成一个名称,就是刚刚JQueryxxxx这一大段,然后这个函数就是success设置的函数,意思如下:

var JQueryxxxxx = function(data){
      console.log(data);
}
//这个赋值的匿名函数就是success的值

深层解析

到了这里就可以进行更深层的剖析,先看个例子

$.ajax({
   url:'xxxx?callback=?',
      data:{
          key : "xxx",
          com : "xxx",
          no : "xxx"
      },
  dataType : 'json',
  success:function(data){
          console.log(data);
      }
})

我使用这段代码依旧可以跨域成功,为什么?

不同处之

  1. 之前讲的dataType用于给jq来判断是不是jsonp,但是这里我没有使用
  2. 我们给url加上了callback=?

原理 :

dataType 是用来告诉jq我即将返回的数据类型是什么,从而使用对应的方法,而json和jsonp实际上都是可以在script执行的文件类型,jq则会使用script元素去获取,如果我们指定为xml,这次jsonp就会失败,因为jq不会用带有src的元素去get获取了,不信可以自己试试,你会发现head不会插入script元素。

根据我的测试,当我们指定dataType 为:jsonp/json的时候会采用script元素作为载体。

使用script只是其中的一小步,更重要的则是callback=?,jq会自动判断,如果当前的url有callback=?这段文字,就是自动将?替换为正确的函数名,上面也说过,可以指定或者jq自己创建名称。

于是这两个条件都达到了,便可以跨域成功。

拓展思维

我们知道$.get(),$.post(),$.getJSON(),这三个方法是基于$.ajax()而来的,加上他们的第三个参数data同样是一个发送到服务器的数据,使用{}对象的形式,那么上面的方式我们还可以这样写

$.get({
    url:'xxx',
    data:{
        key : xxx,
        com : xxx,
        no : xxx
    },
    dataType:"jsonp",
    success:function(data){
        console.log(data);
    }
});

虽然jq规定第一个参数url是必须的,但是如果我们只传一个对象,对象里面加上url依旧可以成功运行。

在使用$.getJSON()方法实现上面的效果我们设置可以省略书写dataType。(因为该方法默认dataType:‘json’)

而$.getScript()虽然也是基于$.ajax,但是他是使用xhr对象作为载体,然后加载完毕后用eval()方法运行,所以你看不到有额外的script元素加入dom中去,为此无法适用jsonp,包括给dataType设置为script也是不行的,他们是相等的效果,除非你把dataType设置为json或者jsonp,那样就没有必要了,强行是不可取的。

以上就是关于jq的jsonp跨域的理解,有需要可以一起探讨。

分类: 锋利的JQuery 标签: 跨域jsonp

评论

暂无评论数据

暂无评论数据

目录