這是我在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 Padding
,JSON
大家這都知道,是一種數據通信格式,而”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+'&p=3&cb=succ&from=superpage';
document.body.appendChild(oScript);
3.不要以為這樣問題就解決了,F12一下,就看到生成了好多<script>
!這是因為我們每輸入一個字符就動態生成一個<script>
,造成了代碼冗余!解決一下:
if(oScript){
document.body.removeChild(oScript);
}
好,這樣,我們的搜索框效果就做好了,因為主要講JSONP部分的工作原理,就不做成百度下拉框那樣了,大家可以自己去布局。當然,真正的百度搜索框還要在此基礎上涉及事件的冒泡取消等等,就不是這里的重點了,不做闡述。
JSONP總結
JSONP是為了傳數據而存在的技術。網頁之間的通信原本有AJAX就夠了,而AJAX因為瀏覽器“同源策略”面對跨域情況就束手無策了。JSONP就這樣被發明了,利用
<script>
的src
屬性不受“同源策略”的控制,“作弊”般地巧妙地逃過了瀏覽器的這一限制。JSONP方法本質是創建
<script>
標簽,其src
指向我們的數據地址。地址后面附帶一個回調函數(名字一般是callback或者是別的什么,就看后臺給我們的是什么了,函數名是我們起的)。然后,聲明這個回調函數。這樣,只要一引入上面的<script>
標簽,就相當于執行了那個回調函數。雖然jQuery把JSONP內置在了AJAX里,但是我們一定要清楚,AJAX和JSONP是完全不一樣的,一定不要混淆!以后我會更新一篇介紹AJAX的文章的。
這里是前端和后臺的交匯之處,想要真正融會貫通,還要學學后臺的知識。我也是在學了PHP之后才把JSONP搞懂的。