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