想知道jsonp到底是怎么实现的?看我,包教会!

javascript/jquery

浏览数:220

2019-3-12

AD:资源代下载服务

不管你好不好,反正我是番茄酱。为啥要写这篇文章呢,因为我想写。

看这个文章的你肯定是想学会jsonp吧(废话),那遇到这个文章是你的福气。我敢保证这是全网最容易看懂的文章。当然,你如果不会写js,不懂什么叫跨域,那就算了。别勉强了,勉强是没有幸福的(而且你也没有学习jsonp实现方法的必要)。

首先声明,这篇文章不涉及后台代码的具体实现,关于后台的部分只说思路。

好啦,那我们开课啦!

总的实现思路

我这篇教程的结构是总-分-总(瞎扯的,实际上是总-随意-随意-…-随意)。我们先来说说总的实现思路。

我们都知道由于“同源策略”(不懂啥是同源策略没关系,反正你知道有跨域现象就行了),而导致我们跨域的ajax请求发送失败,浏览器报错。

但是呢script标签的src是没有跨域一说的,也就是说你可以随便引用别的网站的js。这就是总的实现思路。如果不理解这一点,也不用往下看了,因为你以你的知识储备和理解能力不合适看这文章。

说完总的实现思路,我们来看具体怎么做吧。

1:先忘记我们要实现jsonp

先忘了我们的目标,看一下我们需要完成jsonp而需要掌握的知识。先理解了这些,才能理解jsonp的实现。

1.1:基础的js代码

我们在页面写个这样的代码:

<script>
    function a() {
        console.log('hello cat!');
    }
</script>
<script>
    a();
</script>

运行结果:

对于代码和结果没有异议吧。为啥我要写这样的函数。我要说明的是这样一点:后一个script标签里的代码可以引用前一个script代码里的函数(全局)。老规矩,理解了这点就继续往下看。

1.2:script标签引用文本

我们在html里写这样的代码:

<script>
    function a() {
        console.log('hello cat2!');
    }
</script>

然后我们在同路径下新建一个a.txt。并且a.txt里的文本如下:

a();

然后我们在html里引用a.txt。完整的代码如下:

<script>
    function a() {
        console.log('hello cat2!');
    }
</script>
<script src="a.txt"></script>

刷新页面,控制台如下:

也就是说txt里的代码被执行了。所以a函数才会被执行。我要说明的是:scritpt标签引用的外部文件中的文本内容会被当成js来解析。

也就是说相当于是这样的代码:

<script>
    function a() {
        console.log('hello cat2!');
    }
</script>
<script>
    a();
</script>

1.3:后台返回文本

如果我们的后台给我们返回的不是数据,而是跟a.txt一样的文本如下文本:

a();

如我们请求地址为:https://www.a.com/a。则我们此时的完整代码为:

<script>
    function a() {
        console.log('hello cat2!');
    }
</script>
<script src="https://www.a.com/a"></script>

那可以预见,最终的结果会与1.2一致。因为也等于是如下的代码:

<script>
    function a() {
        console.log('hello cat2!');
    }
</script>
<script>
    a();
</script>

小结

以上的东西只是需要完成jsonp要懂的知识。你理解了可以继续往下看。先不要深究“这样怎么能实现”的问题。不要急,我后面会说的。如果不理解上面的知识可以多看几遍。能够自己动手实验最好。

2:再看看一般的ajax请求

我们一般的ajax请求,是后台给我们一个请求地址,我们发送请求,然后后台返回给我们json格式的信息。例如我们要请求的地址是:

https://www.a.com/userInfo (获取用户信息)

后台应该返回给我们的数据是:

{
  "name": "番茄酱",
  "wechat": "fan_qie_jiang666",
  "qq": "1164431166",
  "email": "1164431166@qq.com"
}

也就是说我们最终需要的是服务器把json格式的数据给我们。但是我们用1里说的方法,虽然服务器能调用我们本地的函数,但是我们怎么能获取到数据呢?

那这样,我们把1.3的html代码改成这样:

<script>
    function a(res) {
        console.log(res);
    }
</script>
<script src="https://www.a.com/userInfo"></script>

服务器返回的文本改成这样:

a({
    "name": "番茄酱",
    "wechat": "fan_qie_jiang666",
    "qq": "1164431166",
    "email": "1164431166@qq.com"
});

也就是相当于这样的代码:

<script>
    function a(res) {
        console.log(res);
    }
</script>
<script>
    a({
        "name": "番茄酱",
        "wechat": "fan_qie_jiang666",
        "qq": "1164431166",
        "email": "1164431166@qq.com"
    });
</script>

最终结果:

也就是说我们获取到了我们需要的数据。但是万一我们的function不叫a,或者原本叫a,但是因为种种原因需要改名,这样后台也要跟着改代码。这增加了沟通成本,也增加了后台的工作量。并且可能每个接口你们都需要去沟通这个函数的名字。这是问题呀!

3.解决函数名的问题

用script标签里的src相当于向服务器发送了get请求。

不管你理不理解上面这点,记住就行了。既然是相当于get请求,那就可以带参。并且后台也能获得这个参数的值。

既然这样那我们是不是跟后台沟通好我们给所有用jsonp的请求弄个参数,这个参数的值是我们本地的函数名。后台直接给我们返回函数名然后参数为数据值就ok辣?不理解的话看下面的过程。

比如我们和后台沟通好参数名叫balabala,那代码就像下面这样:

<script>
    function xiaoMoXian(res) {
        console.log(res);
    }
</script>
<script src="https://www.a.com/userInfo?balabala=xiaoMoXian"></script>

后台收到了这个请求,不再像之前那样直接返回给我们a(…)。

因为我们已经说好了,函数名不再是固定的a,而是balabala这个参数的值才是我们的函数名。

于是后台去获取balabala这个参数的值,获取到的是xiaoMoXian。于是后台返回给我们:

xiaoMoXian({
    "name": "番茄酱",
    "wechat": "fan_qie_jiang666",
    "qq": "1164431166",
    "email": "1164431166@qq.com"
});

于是代码就相当于是:

<script>
    function xiaoMoXian(res) {
        console.log(res);
    }
</script>
<script>
    xiaoMoXian({
        "name": "番茄酱",
        "wechat": "fan_qie_jiang666",
        "qq": "1164431166",
        "email": "1164431166@qq.com"
    });
</script>

最终结果与2相同。

小结

以上就是jsonp的实现过程。我们已经完成了不用ajax来请求,而利用script标签src属性的跨域特性,来实现我们获取数据的目的。

我来小结下我们用到的知识点:

  1. ajax请求受同源策略的影响不能跨域。(问题)
  2. script标签的src是可以跨域的,不受同源策略的影响。(总的方法)
  3. 后一个script标签里的代码可以引用前一个script代码里的函数。
  4. scritpt标签引用的外部文件中的文本内容会被当成js来解析。(结合3可以获取数据)
  5. 用script标签里的src相当于向服务器发送了get请求。(解决函数名的问题)

看到这并且看懂就说明你已经差不多可以毕业了。因为你已经完全懂了jsonp怎么实现的。可是我们一般用jsonp好像没这么麻烦呀,也不用专门去写个函数来给后台调用,也不用去写script标签写src到我们的请求地址,也不用沟通什么参数名。哪像你说的这么麻烦!?

哈哈,我要加班啦。预知后事如何,请多点赞。赞够多我就更。

或者加我微信给我发1块钱红包,众筹到10元我就更(谁还没个身价了 ̄へ ̄)。