一、JSONP的誕生
- 首先,因?yàn)?lt;b>ajax</b>無(wú)法跨域,然后開發(fā)者就有所思考
- 其次,開發(fā)者發(fā)現(xiàn),<b> <script></b>標(biāo)簽的<b>src</b>屬性是可以跨域的
- 把跨域服務(wù)器寫成<b> 調(diào)用本地的函數(shù)</b> ,回調(diào)數(shù)據(jù)回來(lái)不就好了?
- <b>json</b>剛好被js支持(<b>object</b>)
- 調(diào)用跨域服務(wù)器上動(dòng)態(tài)生成的js格式文件(不管是什么類型的地址,最終生成的返回值都是一段js代碼)
- 這種獲取遠(yuǎn)程數(shù)據(jù)的方式看起來(lái)非常像ajax,但其實(shí)并不一樣
- 便于客戶端使用數(shù)據(jù),逐漸形成了一種<b>非正式傳輸協(xié)議</b>,人們把它稱作<b>JSONP</b>。
- 傳遞一個(gè)callback參數(shù)給跨域服務(wù)端,然后跨域服務(wù)端返回?cái)?shù)據(jù)時(shí)會(huì)將這個(gè)callback參數(shù)作為函數(shù)名來(lái)包裹住json數(shù)據(jù)即可。
二、老板,來(lái)一斤栗子。
【栗子一】
跨域服務(wù)器
文件:remote.js
代碼:
alert('我是遠(yuǎn)程文件');
本地
<script type="text/javascript" src="跨域服務(wù)器/remote.js"></script>
這邊做的就是直接引入一個(gè)js,頁(yè)面將會(huì)彈出一個(gè)提示窗體,顯示 我是遠(yuǎn)程文件。
【栗子二】
跨域服務(wù)器
文件:remote.js
代碼:
localHandler({"result":"我是遠(yuǎn)程js帶來(lái)的數(shù)據(jù)"});
本地
<script type="text/javascript">
var localHandler = function(data){
alert('我是本地函數(shù),可以被跨域的remote.js文件調(diào)用,遠(yuǎn)程js帶來(lái)的數(shù)據(jù)是:' + data.result);
};
</script>
<script type="text/javascript" src="跨域服務(wù)器/remote.js"></script>
這邊做的是
1、本地定義一個(gè)函數(shù)
2、引入一個(gè)js
3、被引入的js里面,調(diào)用這個(gè)函數(shù)
頁(yè)面將會(huì)彈出一個(gè)提示窗體。顯示本地函數(shù)被跨域的遠(yuǎn)程js調(diào)用成功,并且還接收到了 我是遠(yuǎn)程js帶來(lái)的數(shù)據(jù)。
新問(wèn)題出現(xiàn)了:讓遠(yuǎn)程js知道它應(yīng)該調(diào)用的本地函數(shù)叫什么名字呢?畢竟是jsonp的服務(wù)者都要面對(duì)很多服務(wù)對(duì)象,而這些服務(wù)對(duì)象各自的本地函數(shù)都不相同???
【栗子三】
跨域服務(wù)端提供的js腳本動(dòng)態(tài)生成,這樣調(diào)用者可以傳一個(gè)參數(shù)過(guò)去告訴跨域服務(wù)端“我想要一段調(diào)用XXX函數(shù)的js代碼,請(qǐng)你返回給我”,于是跨域服務(wù)器就可以按照客戶端的需求來(lái)生成js腳本并響應(yīng)了。
跨域服務(wù)器
文件:flightResult.php
代碼:
flightHandler({
"code":"CA1998",
"price": 1780,
"tickets": 5
});
本地
<script type="text/javascript">
// 得到航班信息查詢結(jié)果后的回調(diào)函數(shù)
var flightHandler = function(data){
alert('你查詢的航班結(jié)果是:票價(jià) ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 張。');
};
// 提供jsonp服務(wù)的url地址(不管是什么類型的地址,最終生成的返回值都是一段javascript代碼)
var url = "跨域服務(wù)器/flightResult.php?code=CA1998&callback=flightHandler";
// 創(chuàng)建script標(biāo)簽,設(shè)置其屬性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script標(biāo)簽加入head,此時(shí)調(diào)用開始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
這次我們做的是
1、動(dòng)態(tài)創(chuàng)建腳本
2、url中傳遞了一個(gè)code參數(shù),服務(wù)器去做查詢CA1998次航班的信息,callback參數(shù)告訴服務(wù)器,我的本地回調(diào)函數(shù)叫做flightHandler
3、跨域服務(wù)端調(diào)用這個(gè)函數(shù)flightHandler
頁(yè)面將會(huì)彈出一個(gè)提示窗體。把票價(jià)、余票以及張數(shù)給傳遞回來(lái)了。
三、那么服務(wù)器到底做了什么呢?
說(shuō)到底,就是拼接字符串。
// 數(shù)據(jù)
$data = [
"name":"anonymous66",
"age":"18",
"like":"jianshu"
];
// 接收callback函數(shù)名稱
$callback = $_GET['callback'];
// 輸出
echo $callback . "(" . json_encode($data) . ")";
四、與AJAX的區(qū)別是什么?
ajax和jsonp本質(zhì)上是不同的東西。
ajax的核心是通過(guò)XmlHttpRequest獲取非本頁(yè)內(nèi)容
jsonp的核心則是動(dòng)態(tài)添加<script>標(biāo)簽來(lái)調(diào)用服務(wù)器提供的js腳本。
五、結(jié)語(yǔ)
本篇文章是對(duì)JSONP的原理掃盲,一般很多開發(fā)者會(huì)使用卻不知道原理,這在學(xué)習(xí)和成長(zhǎng)的路上不算好事。so,知道jsonp原理,你又可以加50塊工資了。