javascript
浅谈JSONP
這是我在13年初寫的文章,當(dāng)時(shí)懵懵懂懂寫下了自己對(duì)JSONP的理解。
文章原文
博客 歡迎訂閱
提到JSONP,我當(dāng)時(shí)在網(wǎng)上找了無數(shù)帖子也沒有看懂它。那些文章大同小異,都是講到JSONP原理以后就戛然而止,把我們這些初學(xué)者搞得云里霧里。所以,寫下這篇文章,希望對(duì)大家有幫助!
為什么要有JSONP
回答這個(gè)問題之前,大家先想想什么是AJAX,JSONP就是一種能夠解決AJAX辦不到的事情而存在的一種取數(shù)據(jù)的技術(shù)。什么事情是AJAX辦不到的呢?就是跨域!
跨域:顧名思義,就是當(dāng)前網(wǎng)頁的地址和我們要取的數(shù)據(jù)地址不在一個(gè)域下。這是因?yàn)闉g覽器都有一個(gè)“同源策略”— 兩個(gè)頁面的域名必須在同域的情況下,才能允許通信。
怎么才算一個(gè)域呢?
相同域名,相同端口,相同協(xié)議(因?yàn)椴皇沁@里的重點(diǎn),大家可以請(qǐng)教Google)
“同源策略”的意義:“同源策略”有效地阻止了一些危險(xiǎn)行為,比如你進(jìn)入www.aaa.com,同時(shí)瀏覽器又開了一個(gè)www.bbb.com,如果這個(gè)www.bbb.com是一個(gè)木馬網(wǎng)站,在沒有“同源策略”的情況下,它就可能嵌入一些代碼,來取得你在www.aaa.com的信息(因?yàn)檫@時(shí)兩個(gè)頁面是可以通信的) 。而正是因?yàn)橛辛恕巴床呗浴?#xff0c;剛才可以通信的情況才不會(huì)發(fā)生。
“同源策略”帶來的麻煩:上面的例子是我們?cè)诓恢榈那闆r下,保護(hù)我們的網(wǎng)絡(luò)安全的,但如果我們就是要讓www.aaa.com取得www.bbb.com上的數(shù)據(jù),行不行呢?答:不行!還是因?yàn)椤蓖床呗浴?#xff01;我們想從自己信任的網(wǎng)頁上取得數(shù)據(jù)都不行,這可怎么辦呢?
JSONP出現(xiàn)
在需要跨域通信的歲月里,一些卓越的前端工程師們想到了這個(gè)”作弊”的辦法來逃避”同源策略”。”同源策略”雖然很厲害,阻止了一個(gè)頁面到另一個(gè)頁面的通信,可是src指向的路徑它放過了,提到src,大家是不是想起了<script>?對(duì),JSONP就是利用”同源策略”的這一”漏洞”來進(jìn)行”作弊”的。(其實(shí)有src屬性的不止有<script>,還有<img>和<iframe>,而<iframe>也是能夠運(yùn)用JSONP的)。
下面看看JSONP的原理:
JSONP:JSON with Padding,JSON大家這都知道,是一種數(shù)據(jù)通信格式,而”Padding”是什么意思,別急,往下看就知道了。
我們先舉一個(gè)簡(jiǎn)單的例子:
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});頁面會(huì)彈出risker,有感覺了么?
JSONP是這樣工作的:像前面所說的那樣,我們可以取到www.bbb.com/abc.js,里面是一個(gè)abc函數(shù),這個(gè)函數(shù)也會(huì)被加載到www.aaa.com。加載完成后,就應(yīng)該執(zhí)行abc了,然后我們?cè)趙ww.aaa.com定義abc函數(shù),這個(gè)函數(shù)里寫一些處理數(shù)據(jù)的語句。這樣其實(shí)就簡(jiǎn)單地實(shí)現(xiàn)了跨域訪問數(shù)據(jù)了,這也就是JSONP的原理了。而JSON with Padding的意思,就是abc(json)中的json:
abc({'name':'risker','age':24})。
這個(gè)JSON對(duì)象被包在abc這個(gè)函數(shù)中當(dāng)作參數(shù)來被處理,而JSON with Padding這個(gè)詞很形象地形容了這個(gè)過程。
JSONP的簡(jiǎn)單實(shí)例
在網(wǎng)上能找到的JSON基本只是介紹到這里就完了,但是這讓初學(xué)者看不到一個(gè)實(shí)實(shí)在在的例子。所以下面才是這篇文章和其他網(wǎng)上介紹JSON文章不一樣的地方,我?guī)Ыo大家一個(gè)例子!
大家一定對(duì)百度的自動(dòng)搜索框有印象,它就是一個(gè)JSONP的實(shí)例:
先查看demo
分析一下:
1.分析數(shù)據(jù)地址回顧上面的例子,我們首先要知道數(shù)據(jù)的來源地址,就是上面的www.bbb.com/abc.js里的數(shù)據(jù)。在Chrome中查看Network。然后隨便在搜索框里輸入點(diǎn)什么,比如s,觀察Network里是不是多了東西,點(diǎn)開它,就是我們輸入“s”后傳回的數(shù)據(jù)了:
這個(gè)地址是http://suggestion.baidu.com/su?wd=S&p=3&cb=window.bdsug.sug&from=superpage&t=1365392859833 , 我們分析一下,wd后面是s,那就可以斷定百度定義wd是搜索的關(guān)鍵字,cb是一個(gè)回調(diào)函數(shù),其他的對(duì)我們就不重要了。回調(diào)函數(shù)是我們?nèi)〉綌?shù)據(jù)要后執(zhí)行的函數(shù),相當(dāng)于我們上面的abc函數(shù)。它是可以自己取名的。像http://suggestion.baidu.com/su?wd=S&p=3&cb=succ&from=superpage表示取到數(shù)據(jù)后執(zhí)行succ函數(shù):
這樣,我們的數(shù)據(jù)就包在了succ函數(shù)里做一個(gè)參數(shù),再次證明了JSON with Padding 的原理。
2.做<script>標(biāo)簽,其src指向數(shù)據(jù)地址:這是要?jiǎng)討B(tài)生成的,不能把地址寫死,要不然取到的都是一樣的數(shù)據(jù)了。所以我們要?jiǎng)討B(tài)生成<script>,動(dòng)態(tài)指定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>!這是因?yàn)槲覀兠枯斎胍粋€(gè)字符就動(dòng)態(tài)生成一個(gè)<script>,造成了代碼冗余!解決一下:
if(oScript){ document.body.removeChild(oScript); }好,這樣,我們的搜索框效果就做好了,因?yàn)橹饕vJSONP部分的工作原理,就不做成百度下拉框那樣了,大家可以自己去布局。當(dāng)然,真正的百度搜索框還要在此基礎(chǔ)上涉及事件的冒泡取消等等,就不是這里的重點(diǎn)了,不做闡述。
JSONP總結(jié)
JSONP是為了傳數(shù)據(jù)而存在的技術(shù)。網(wǎng)頁之間的通信原本有AJAX就夠了,而AJAX因?yàn)闉g覽器“同源策略”面對(duì)跨域情況就束手無策了。JSONP就這樣被發(fā)明了,利用<script>的src屬性不受“同源策略”的控制,“作弊”般地巧妙地逃過了瀏覽器的這一限制。
JSONP方法本質(zhì)是創(chuàng)建<script>標(biāo)簽,其src指向我們的數(shù)據(jù)地址。地址后面附帶一個(gè)回調(diào)函數(shù)(名字一般是callback或者是別的什么,就看后臺(tái)給我們的是什么了,函數(shù)名是我們起的)。然后,聲明這個(gè)回調(diào)函數(shù)。這樣,只要一引入上面的<script>標(biāo)簽,就相當(dāng)于執(zhí)行了那個(gè)回調(diào)函數(shù)。
雖然jQuery把JSONP內(nèi)置在了AJAX里,但是我們一定要清楚,AJAX和JSONP是完全不一樣的,一定不要混淆!以后我會(huì)更新一篇介紹AJAX的文章的。
這里是前端和后臺(tái)的交匯之處,想要真正融會(huì)貫通,還要學(xué)學(xué)后臺(tái)的知識(shí)。我也是在學(xué)了PHP之后才把JSONP搞懂的。
總結(jié)
- 上一篇: Java判断两个Date是不是同一天
- 下一篇: SpringBoot解决ajax跨域问题