?摘自:http://www.qdfuns.com/notes/16738/1b6ad6125747d28592a53a960b44c6f4.html
什么是JSONP?
先說說JSONP是怎么產(chǎn)生的:
其實網(wǎng)上關于JSONP的講解有很多负饲,但卻千篇一律洽胶,而且云里霧里侨艾,對于很多剛接觸的人來講理解起來有些困難吨悍,著用自己的方式來闡釋一下這個問題鼻弧,看看是否有幫助习霹。
1、一個眾所周知的問題加匈,Ajax直接請求普通文件存在跨域無權限訪問的問題存璃,甭管你是靜態(tài)頁面、動態(tài)網(wǎng)頁雕拼、web服務纵东、WCF,只要是跨域請求啥寇,一律不準偎球。
2、不過我們又發(fā)現(xiàn)辑甜,Web頁面上調用js文件時則不受是否跨域的影響(不僅如此衰絮,我們還發(fā)現(xiàn)凡是擁有"src"這個屬性的標簽都擁有跨域的能力,比如栈戳、岂傲、)难裆。
3子檀、于是可以判斷,當前階段如果想通過純web端(ActiveX控件乃戈、服務端代理褂痰、屬于未來的HTML5之Websocket等方式不算)跨域訪問數(shù)據(jù)就只有一種可能,那就是在遠程服務器上設法把數(shù)據(jù)裝進js格式的文件里症虑,供客戶端調用和進一步處理缩歪。
4、恰巧我們已經(jīng)知道有一種叫做JSON的純字符數(shù)據(jù)格式可以簡潔的描述復雜數(shù)據(jù)谍憔,更妙的是JSON還被js原生支持匪蝙,所以在客戶端幾乎可以隨心所欲的處理這種格式的數(shù)據(jù)。
5习贫、這樣子解決方案就呼之欲出了逛球,web客戶端通過與調用腳本一模一樣的方式,來調用跨域服務器上動態(tài)生成的js格式文件(一般以JSON為后綴)苫昌,顯而易見颤绕,服務器之所以要動態(tài)生成JSON文件,目的就在于把客戶端需要的數(shù)據(jù)裝入進去。
6奥务、客戶端在對JSON文件調用成功之后物独,也就獲得了自己所需的數(shù)據(jù),剩下的就是按照自己需求進行處理和展現(xiàn)了氯葬,這種獲取遠程數(shù)據(jù)的方式看起來非常像AJAX挡篓,但其實并不一樣。
7帚称、為了便于客戶端使用數(shù)據(jù)瞻凤,逐漸形成了一種非正式傳輸協(xié)議,人們把它稱作JSONP世杀,該協(xié)議的一個要點就是允許用戶傳遞一個callback參數(shù)給服務端阀参,然后服務端返回數(shù)據(jù)時會將這個callback參數(shù)作為函數(shù)名來包裹住JSON數(shù)據(jù),這樣客戶端就可以隨意定制自己的函數(shù)來自動處理返回數(shù)據(jù)了瞻坝。
如果對于callback參數(shù)如何使用還有些模糊的話蛛壳,我們后面會有具體的實例來講解。
JSONP的客戶端具體實現(xiàn):
不管jQuery也好所刀,extjs也罷衙荐,又或者是其他支持jsonp的框架,他們幕后所做的工作都是一樣的浮创,下面我來循序漸進的說明一下jsonp在客戶端的實現(xiàn):
1忧吟、我們知道,哪怕跨域js文件中的代碼(當然指符合web腳本安全策略的)斩披,web頁面也是可以無條件執(zhí)行的溜族。
遠程服務器remoteserver.com根目錄下有個remote.js文件代碼如下:
本地服務器localserver.com下有個jsonp.html頁面代碼如下:
毫無疑問,頁面將會彈出一個提示窗體垦沉,顯示跨域調用成功煌抒。
2、現(xiàn)在我們在jsonp.html頁面定義一個函數(shù)厕倍,然后在遠程remote.js中傳入數(shù)據(jù)進行調用寡壮。
jsonp.html頁面代碼如下:
remote.js文件代碼如下:
運行之后查看結果,頁面成功彈出提示窗口讹弯,顯示本地函數(shù)被跨域的遠程js調用成功况既,并且還接收到了遠程js帶來的數(shù)據(jù)。
很欣喜组民,跨域遠程獲取數(shù)據(jù)的目的基本實現(xiàn)了棒仍,但是又一個問題出現(xiàn)了,我怎么讓遠程js知道它應該調用的本地函數(shù)叫什么名字呢邪乍?畢竟是jsonp的服務者都要面對很多服務對象降狠,而這些服務對象各自的本地函數(shù)都不相同岸钥ⅰ?我們接著往下看榜配。
3否纬、聰明的開發(fā)者很容易想到,只要服務端提供的js腳本是動態(tài)生成的就行了唄蛋褥,這樣調用者可以傳一個參數(shù)過去告訴服務端 "我想要一段調用XXX函數(shù)的js代碼临燃,請你返回給我",于是服務器就可以按照客戶端的需求來生成js腳本并響應了烙心。
看jsonp.html頁面的代碼:
這次的代碼變化比較大膜廊,不再直接把遠程js文件寫死,而是編碼實現(xiàn)動態(tài)查詢淫茵,而這也正是jsonp客戶端實現(xiàn)的核心部分爪瓜,本例中的重點也就在于如何完成jsonp調用的全過程。
我們看到調用的url中傳遞了一個code參數(shù)匙瘪,告訴服務器我要查的是CA1998次航班的信息铆铆,而callback參數(shù)則告訴服務器,我的本地回調函數(shù)叫做flightHandler丹喻,所以請把查詢結果傳入這個函數(shù)中進行調用薄货。
OK,服務器很聰明碍论,這個叫做flightResult.aspx的頁面生成了一段這樣的代碼提供給jsonp.html
(服務端的實現(xiàn)這里就不演示了谅猾,與你選用的語言無關,說到底就是拼接字符串):
我們看到鳍悠,傳遞給flightHandler函數(shù)的是一個json税娜,它描述了航班的基本信息。運行一下頁面贼涩,成功彈出提示窗口巧涧,jsonp的執(zhí)行全過程順利完成!
4遥倦、到這里為止的話,相信你已經(jīng)能夠理解jsonp的客戶端實現(xiàn)原理了吧占锯?剩下的就是如何把代碼封裝一下袒哥,以便于與用戶界面交互,從而實現(xiàn)多次和重復調用消略。
jQuery如何實現(xiàn)jsonp調用堡称?
是不是有點奇怪?為什么我這次沒有寫flightHandler這個函數(shù)呢艺演?而且竟然也運行成功了却紧!
這就是jQuery的功勞了桐臊,jquery在處理jsonp類型的ajax時(,雖然jquery也把jsonp歸入了ajax晓殊,但其實它們真的不是一回事兒)断凶,自動幫你生成回調函數(shù)并把數(shù)據(jù)取出來供success屬性方法來調用,是不是很爽呀巫俺?
[attachimg][attachimg]
補充
這里針對ajax與jsonp的異同再做一些補充說明:
1认烁、ajax和jsonp這兩種技術在調用方式上"看起來"很像,目的也一樣介汹,都是請求一個url却嗡,然后把服務器返回的數(shù)據(jù)進行處理,因此jquery和ext等框架都把jsonp作為ajax的一種形式進行了封裝嘹承。
2窗价、但ajax和jsonp其實本質上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內容叹卷,而jsonp的核心則是動態(tài)添加標簽來調用服務器提供的js腳本舌镶。
3、所以說豪娜,其實ajax與jsonp的區(qū)別不在于是否跨域餐胀,ajax通過服務端代理一樣可以實現(xiàn)跨域,jsonp本身也不排斥同域的數(shù)據(jù)的獲取瘤载。
4否灾、還有就是,jsonp是一種方式或者說非強制性協(xié)議鸣奔,如同ajax一樣墨技,它也不一定非要用json格式來傳遞數(shù)據(jù),如果你愿意挎狸,字符串都行扣汪,只不過這樣不利于用jsonp提供公開服務。
總而言之锨匆,jsonp不是ajax的一個特例崭别,哪怕jquery等巨頭把jsonp封裝進了ajax,也不能改變這一點恐锣!