Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浅谈JSONP #6

Open
riskers opened this issue Sep 14, 2015 · 1 comment
Open

浅谈JSONP #6

riskers opened this issue Sep 14, 2015 · 1 comment
Labels
FE web 前端

Comments

@riskers
Copy link
Owner

riskers commented Sep 14, 2015

这是我在13年初写的文章,当时懵懵懂懂写下了自己对JSONP的理解。


提到JSONP,我当时在网上找了无数帖子也没有看懂它。那些文章大同小异,都是讲到JSONP原理以后就戛然而止,把我们这些初学者搞得云里雾里。所以,写下这篇文章,希望对大家有帮助!

为什么要有JSONP

回答这个问题之前,大家先想想什么是AJAX,JSONP就是一种能够解决AJAX办不到的事情而存在的一种取数据的技术。什么事情是AJAX办不到的呢?就是跨域!

跨域:顾名思义,就是当前网页的地址和我们要取的数据地址不在一个域下。这是因为浏览器都有一个“同源策略”— 两个页面的域名必须在同域的情况下,才能允许通信。

怎么才算一个域呢?

相同域名,相同端口,相同协议(因为不是这里的重点,大家可以请教Google)

“同源策略”的意义:“同源策略”有效地阻止了一些危险行为,比如你进入www.aaa.com,同时浏览器又开了一个www.bbb.com,如果这个www.bbb.com是一个木马网站,在没有“同源策略”的情况下,它就可能嵌入一些代码,来取得你在www.aaa.com的信息(因为这时两个页面是可以通信的) 。而正是因为有了“同源策略”,刚才可以通信的情况才不会发生。

“同源策略”带来的麻烦:上面的例子是我们在不知情的情况下,保护我们的网络安全的,但如果我们就是要让www.aaa.com取得www.bbb.com上的数据,行不行呢?答:不行!还是因为”同源策略”!我们想从自己信任的网页上取得数据都不行,这可怎么办呢?

JSONP出现

在需要跨域通信的岁月里,一些卓越的前端工程师们想到了这个”作弊”的办法来逃避”同源策略”。”同源策略”虽然很厉害,阻止了一个页面到另一个页面的通信,可是src指向的路径它放过了,提到src,大家是不是想起了<script>?对,JSONP就是利用”同源策略”的这一”漏洞”来进行”作弊”的。(其实有src属性的不止有<script>,还有<img><iframe>,而<iframe>也是能够运用JSONP的)。

下面看看JSONP的原理:

JSONP:JSON with PaddingJSON大家这都知道,是一种数据通信格式,而”Padding”是什么意思,别急,往下看就知道了。

我们先举一个简单的例子:

www.aaa.com中:

<script type="text/javascript" src="http://www.bbb.com/abc.js"></script>
<script type="text/javascript">
    function abc(json){
        alert(json['name']); 
    }
</script>

www.bbb.com/abc.js中:

abc({'name':'risker','age':24});

页面会弹出risker,有感觉了么?

JSONP是这样工作的:像前面所说的那样,我们可以取到www.bbb.com/abc.js,里面是一个abc函数,这个函数也会被加载到www.aaa.com。加载完成后,就应该执行abc了,然后我们在www.aaa.com定义abc函数,这个函数里写一些处理数据的语句。这样其实就简单地实现了跨域访问数据了,这也就是JSONP的原理了。而JSON with Padding的意思,就是abc(json)中的json
abc({'name':'risker','age':24})

这个JSON对象被包在abc这个函数中当作参数来被处理,而JSON with Padding这个词很形象地形容了这个过程。

JSONP的简单实例

在网上能找到的JSON基本只是介绍到这里就完了,但是这让初学者看不到一个实实在在的例子。所以下面才是这篇文章和其他网上介绍JSON文章不一样的地方,我带给大家一个例子!
大家一定对百度的自动搜索框有印象,它就是一个JSONP的实例:

先查看demo

分析一下:

  1. 分析数据地址回顾上面的例子,我们首先要知道数据的来源地址,就是上面的www.bbb.com/abc.js里的数据。在Chrome中查看Network。然后随便在搜索框里输入点什么,比如s,观察Network里是不是多了东西,点开它,就是我们输入“s”后传回的数据了:

    这个地址是 http://suggestion.baidu.com/su?wd=S&p=3&cb=window.bdsug.sug&from=superpage&t=1365392859833 , 我们分析一下,wd后面是s,那就可以断定百度定义wd是搜索的关键字,cb是一个回调函数,其他的对我们就不重要了。回调函数是我们取到数据要后执行的函数,相当于我们上面的abc函数。它是可以自己取名的。像http://suggestion.baidu.com/su?wd=S&p=3&cb=succ&from=superpage表示取到数据后执行succ函数:

    这样,我们的数据就包在了succ函数里做一个参数,再次证明了JSON with Padding 的原理。

  2. <script>标签,其src指向数据地址:这是要动态生成的,不能把地址写死,要不然取到的都是一样的数据了。所以我们要动态生成<script>,动态指定src属性:

    var oScript = document.createElement('script');
    oScript.src = 'http://suggestion.baidu.com/su?wd='+oTxt.value+'&amp;p=3&amp;cb=succ&amp;from=superpage';
    document.body.appendChild(oScript);
    
  3. 不要以为这样问题就解决了,F12一下,就看到生成了好多<script>!这是因为我们每输入一个字符就动态生成一个<script>,造成了代码冗余!解决一下:

    if(oScript){
        document.body.removeChild(oScript);
    }
    

    好,这样,我们的搜索框效果就做好了,因为主要讲JSONP部分的工作原理,就不做成百度下拉框那样了,大家可以自己去布局。当然,真正的百度搜索框还要在此基础上涉及事件的冒泡取消等等,就不是这里的重点了,不做阐述。

JSONP总结

  1. JSONP是为了传数据而存在的技术。网页之间的通信原本有AJAX就够了,而AJAX因为浏览器“同源策略”面对跨域情况就束手无策了。JSONP就这样被发明了,利用<script>src属性不受“同源策略”的控制,“作弊”般地巧妙地逃过了浏览器的这一限制。
  2. JSONP方法本质是创建<script>标签,其src指向我们的数据地址。地址后面附带一个回调函数(名字一般是callback或者是别的什么,就看后台给我们的是什么了,函数名是我们起的)。然后,声明这个回调函数。这样,只要一引入上面的<script>标签,就相当于执行了那个回调函数。
  3. 虽然jQuery把JSONP内置在了AJAX里,但是我们一定要清楚,AJAX和JSONP是完全不一样的,一定不要混淆!以后我会更新一篇介绍AJAX的文章的。
  4. 这里是前端和后台的交汇之处,想要真正融会贯通,还要学学后台的知识。我也是在学了PHP之后才把JSONP搞懂的。

向我捐助 | 关于我 | 工作机会


@sphenginx
Copy link

#learn that

@riskers riskers removed the label Sep 15, 2015
@riskers riskers added FE web 前端 and removed jsonp labels Dec 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FE web 前端
Projects
None yet
Development

No branches or pull requests

2 participants