本文轉自模闲,博客園查剖,昵稱:[隨它去吧]贯被,
http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html
非常感謝。
前言:
說到AJAX就會不可避免的面臨兩個問題咳胃,第一個是AJAX以何種格式來交換數(shù)據植康?第二個是跨域的需求如何解決?這兩個問題目前都有不同的解決方案拙绊,比如數(shù)據可以用自定義字符串或者用XML來描述向图,跨域可以通過服務器端代理來解決泳秀。
但到目前為止最被推崇或者說首選的方案還是用JSON來傳數(shù)據标沪,靠JSONP來跨域榄攀。而這就是本文將要講述的內容。
JSON和JSONP雖然只有一個字母的差別金句,但其實他們根本不是一回事兒:JSON是一種數(shù)據交換格式檩赢,而JSONP是一種依靠開發(fā)人員的聰明才智創(chuàng)造出的一種非官方跨域數(shù)據交互協(xié)議。我們拿最近比較火的諜戰(zhàn)片來打個比方违寞,JSON是地下黨們用來書寫和交換情報的“暗號”贞瞒,而JSONP則是把用暗號書寫的情報傳遞給自己同志時使用的接頭方式〕寐看到沒军浆?一個是描述信息的格式,一個是信息傳遞雙方約定的方法挡闰。
既然隨便聊聊乒融,那我們就不再采用教條的方式來講述,而是把關注重心放在幫助開發(fā)人員理解是否應當選擇使用以及如何使用上摄悯。
什么是JSON赞季?
前面簡單說了一下,JSON是一種基于文本的數(shù)據交換方式奢驯,或者叫做數(shù)據描述格式申钩,你是否該選用他首先肯定要關注它所擁有的優(yōu)點。
JSON的優(yōu)點:
1瘪阁、基于純文本撒遣,跨平臺傳遞極其簡單;
2管跺、Javascript原生支持义黎,后臺語言幾乎全部支持;
3伙菜、輕量級數(shù)據格式轩缤,占用字符數(shù)量極少,特別適合互聯(lián)網傳遞贩绕;
4火的、可讀性較強,雖然比不上XML那么一目了然淑倾,但在合理的依次縮進之后還是很容易識別的馏鹤;
5、容易編寫和解析娇哆,當然前提是你要知道數(shù)據結構湃累;
JSON的缺點當然也有勃救,但在作者看來實在是無關緊要的東西,所以不再單獨說明治力。
JSON的格式或者叫規(guī)則:
JSON能夠以非常簡單的方式來描述數(shù)據結構蒙秒,XML能做的它都能做,因此在跨平臺方面兩者完全不分伯仲宵统。
1晕讲、JSON只有兩種數(shù)據類型描述符,大括號{}和方括號[]马澈,其余英文冒號:是映射符瓢省,英文逗號,是分隔符,英文雙引號""是定義符痊班。
2勤婚、大括號{}用來描述一組“不同類型的無序鍵值對集合”(每個鍵值對可以理解為OOP的屬性描述),方括號[]用來描述一組“相同類型的有序數(shù)據集合”(可對應OOP的數(shù)組)涤伐。
3馒胆、上述兩種集合中若有多個子項,則通過英文逗號,進行分隔废亭。
4国章、鍵值對以英文冒號:進行分隔,并且建議鍵名都加上英文雙引號""豆村,以便于不同語言的解析液兽。
5、JSON內部常用數(shù)據類型無非就是字符串掌动、數(shù)字四啰、布爾、日期粗恢、null 這么幾個柑晒,字符串必須用雙引號引起來,其余的都不用眷射,日期類型比較特殊匙赞,這里就不展開講述了,只是建議如果客戶端沒有按日期排序功能需求的話妖碉,那么把日期時間直接作為字符串傳遞就好涌庭,可以省去很多麻煩。
JSON實例:
// 描述一個人var person = { "Name": "Bob", "Age": 32, "Company": "IBM", "Engineer": true}// 獲取這個人的信息var personAge = person.Age;// 描述幾個人var members = [ { "Name": "Bob", "Age": 32, "Company": "IBM", "Engineer": true }, { "Name": "John", "Age": 20, "Company": "Oracle", "Engineer": false }, { "Name": "Henry", "Age": 45, "Company": "Microsoft", "Engineer": false }]// 讀取其中John的公司名稱var johnsCompany = members[1].Company;// 描述一次會議var conference = { "Conference": "Future Marketing", "Date": "2012-6-1", "Address": "Beijing", "Members": [ { "Name": "Bob", "Age": 32, "Company": "IBM", "Engineer": true }, { "Name": "John", "Age": 20, "Company": "Oracle", "Engineer": false }, { "Name": "Henry", "Age": 45, "Company": "Microsoft", "Engineer": false } ]}// 讀取參會者Henry是否工程師var henryIsAnEngineer = conference.Members[2].Engineer;
關于JSON欧宜,就說這么多坐榆,更多細節(jié)請在開發(fā)過程中查閱資料深入學習。
什么是JSONP冗茸?
先說說JSONP是怎么產生的:
其實網上關于JSONP的講解有很多席镀,但卻千篇一律匹中,而且云里霧里,對于很多剛接觸的人來講理解起來有些困難豪诲,小可不才顶捷,試著用自己的方式來闡釋一下這個問題,看看是否有幫助跛溉。
1焊切、一個眾所周知的問題扮授,Ajax直接請求普通文件存在跨域無權限訪問的問題芳室,甭管你是靜態(tài)頁面、動態(tài)網頁刹勃、web服務堪侯、WCF,只要是跨域請求荔仁,一律不準伍宦;
2、不過我們又發(fā)現(xiàn)乏梁,Web頁面上調用js文件時則不受是否跨域的影響(不僅如此次洼,我們還發(fā)現(xiàn)凡是擁有"src"這個屬性的標簽都擁有跨域的能力,比如遇骑、卖毁、);
3落萎、于是可以判斷亥啦,當前階段如果想通過純web端(ActiveX控件、服務端代理练链、屬于未來的HTML5之Websocket等方式不算)跨域訪問數(shù)據就只有一種可能翔脱,那就是在遠程服務器上設法把數(shù)據裝進js格式的文件里,供客戶端調用和進一步處理媒鼓;
4届吁、恰巧我們已經知道有一種叫做JSON的純字符數(shù)據格式可以簡潔的描述復雜數(shù)據,更妙的是JSON還被js原生支持绿鸣,所以在客戶端幾乎可以隨心所欲的處理這種格式的數(shù)據疚沐;
5、這樣子解決方案就呼之欲出了枚驻,web客戶端通過與調用腳本一模一樣的方式濒旦,來調用跨域服務器上動態(tài)生成的js格式文件(一般以JSON為后綴),顯而易見再登,服務器之所以要動態(tài)生成JSON文件尔邓,目的就在于把客戶端需要的數(shù)據裝入進去晾剖。
6、客戶端在對JSON文件調用成功之后梯嗽,也就獲得了自己所需的數(shù)據齿尽,剩下的就是按照自己需求進行處理和展現(xiàn)了,這種獲取遠程數(shù)據的方式看起來非常像AJAX灯节,但其實并不一樣循头。
7、為了便于客戶端使用數(shù)據炎疆,逐漸形成了一種非正式傳輸協(xié)議卡骂,人們把它稱作JSONP,該協(xié)議的一個要點就是允許用戶傳遞一個callback參數(shù)給服務端形入,然后服務端返回數(shù)據時會將這個callback參數(shù)作為函數(shù)名來包裹住JSON數(shù)據全跨,這樣客戶端就可以隨意定制自己的函數(shù)來自動處理返回數(shù)據了。
如果對于callback參數(shù)如何使用還有些模糊的話亿遂,我們后面會有具體的實例來講解浓若。
JSONP的客戶端具體實現(xiàn):
不管jQuery也好,extjs也罷,又或者是其他支持jsonp的框架,他們幕后所做的工作都是一樣的押蚤,下面我來循序漸進的說明一下jsonp在客戶端的實現(xiàn):
1、我們知道碌上,哪怕跨域js文件中的代碼(當然指符合web腳本安全策略的),web頁面也是可以無條件執(zhí)行的挽放。
遠程服務器remoteserver.com根目錄下有個remote.js文件代碼如下:
alert('我是遠程文件');
本地服務器localserver.com下有個jsonp.html頁面代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script type="text/javascript" src="http://remoteserver.com/remote.js"></script></head><body></body></html>
毫無疑問绍赛,頁面將會彈出一個提示窗體,顯示跨域調用成功辑畦。
2吗蚌、現(xiàn)在我們在jsonp.html頁面定義一個函數(shù),然后在遠程remote.js中傳入數(shù)據進行調用纯出。
jsonp.html頁面代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script type="text/javascript"> var localHandler = function(data){ alert('我是本地函數(shù)蚯妇,可以被跨域的remote.js文件調用,遠程js帶來的數(shù)據是:' + data.result); }; </script> <script type="text/javascript" src="http://remoteserver.com/remote.js"></script></head><body></body></html>
remote.js文件代碼如下:
localHandler({"result":"我是遠程js帶來的數(shù)據"});
運行之后查看結果暂筝,頁面成功彈出提示窗口箩言,顯示本地函數(shù)被跨域的遠程js調用成功,并且還接收到了遠程js帶來的數(shù)據焕襟。很欣喜陨收,跨域遠程獲取數(shù)據的目的基本實現(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({ "code": "CA1998", "price": 1780, "tickets": 5});
我們看到,傳遞給flightHandler函數(shù)的是一個json宏娄,它描述了航班的基本信息问裕。運行一下頁面,成功彈出提示窗口孵坚,jsonp的執(zhí)行全過程順利完成粮宛!
4、到這里為止的話卖宠,相信你已經能夠理解jsonp的客戶端實現(xiàn)原理了吧巍杈?剩下的就是如何把代碼封裝一下,以便于與用戶界面交互扛伍,從而實現(xiàn)多次和重復調用筷畦。
什么?你用的是jQuery刺洒,想知道jQuery如何實現(xiàn)jsonp調用鳖宾?好吧亚斋,那我就好人做到底,再給你一段jQuery使用jsonp的代碼(我們依然沿用上面那個航班信息查詢的例子攘滩,假定返回jsonp結果不變):
是不是有點奇怪帅刊?為什么我這次沒有寫flightHandler這個函數(shù)呢?而且竟然也運行成功了漂问!哈哈赖瞒,這就是jQuery的功勞了,jquery在處理jsonp類型的ajax時(還是忍不住吐槽蚤假,雖然jquery也把jsonp歸入了ajax栏饮,但其實它們真的不是一回事兒),自動幫你生成回調函數(shù)并把數(shù)據取出來供success屬性方法來調用磷仰,是不是很爽呀袍嬉?
好啦,寫到這里灶平,我已經無力再寫下去伺通,又困又累,得趕緊睡覺逢享。朋友們要是看這不錯罐监,覺得有啟發(fā),給點個“推薦”唄瞒爬!由于實在比較簡單弓柱,所以就不再提供demo源碼下載了。
4月20日下午的補充:
沒想到上了博客園的頭條推薦侧但∈缚眨看到大家對這篇文章的認可和評論,還是很開心的禀横,這里針對ajax與jsonp的異同再做一些補充說明:
1屁药、ajax和jsonp這兩種技術在調用方式上“看起來”很像,目的也一樣燕侠,都是請求一個url者祖,然后把服務器返回的數(shù)據進行處理,因此jquery和ext等框架都把jsonp作為ajax的一種形式進行了封裝绢彤;
2七问、但ajax和jsonp其實本質上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內容茫舶,而jsonp的核心則是動態(tài)添加標簽來調用服務器提供的js腳本械巡。
3、所以說,其實ajax與jsonp的區(qū)別不在于是否跨域讥耗,ajax通過服務端代理一樣可以實現(xiàn)跨域有勾,jsonp本身也不排斥同域的數(shù)據的獲取。
4古程、還有就是蔼卡,jsonp是一種方式或者說非強制性協(xié)議,如同ajax一樣挣磨,它也不一定非要用json格式來傳遞數(shù)據雇逞,如果你愿意,字符串都行茁裙,只不過這樣不利于用jsonp提供公開服務塘砸。
總而言之,jsonp不是ajax的一個特例晤锥,哪怕jquery等巨頭把jsonp封裝進了ajax掉蔬,也不能改變著一點!
作者:戰(zhàn)神飄雪
鏈接:http://www.reibang.com/p/860ffb8f8826
來源:簡書
簡書著作權歸作者所有矾瘾,任何形式的轉載都請聯(lián)系作者獲得授權并注明出處女轿。