JSON與JSONP

JSON和JSONP的區(qū)別

簡(jiǎn)要來(lái)說(shuō)JSON是數(shù)據(jù)交換格式浊竟,JSONP是實(shí)現(xiàn)跨域的一種方法

什么是JSON

JSON是一種基于文本的數(shù)據(jù)交換方式,或者叫做數(shù)據(jù)描述格式腌逢。

JSON的格式或者叫規(guī)則

JSON能夠以非常簡(jiǎn)單的方式來(lái)描述數(shù)據(jù)結(jié)構(gòu)降淮,XML能做的它都能做,因此在跨平臺(tái)方面兩者完全不分伯仲搏讶。

  • JSON只有兩種數(shù)據(jù)類(lèi)型描述符佳鳖,大括號(hào){}和方括號(hào)[],其余英文冒號(hào):是映射符媒惕,英文逗號(hào),是分隔符系吩,英文雙引號(hào)""是定義符。
  • 大括號(hào){}用來(lái)描述一組“不同類(lèi)型的無(wú)序鍵值對(duì)集合”(每個(gè)鍵值對(duì)可以理解為OOP的屬性描述)妒蔚,方括號(hào)[]用來(lái)描述一組“相同類(lèi)型的有序數(shù)據(jù)集合”(可對(duì)應(yīng)OOP的數(shù)組)穿挨。
  • 上述兩種集合中若有多個(gè)子項(xiàng)月弛,則通過(guò)英文逗號(hào),進(jìn)行分隔。
  • 鍵值對(duì)以英文冒號(hào):進(jìn)行分隔科盛,并且建議鍵名都加上英文雙引號(hào)""帽衙,以便于不同語(yǔ)言的解析。
  • JSON內(nèi)部常用數(shù)據(jù)類(lèi)型無(wú)非就是字符串贞绵、數(shù)字厉萝、布爾、日期榨崩、null 這么幾個(gè)谴垫,字符串必須用雙引號(hào)引起來(lái),其余的都不用母蛛,日期類(lèi)型比較特殊翩剪,這里就不展開(kāi)講述了,只是建議如果客戶(hù)端沒(méi)有按日期排序功能需求的話(huà)彩郊,那么把日期時(shí)間直接作為字符串傳遞就好前弯,可以省去很多麻煩。
// 描述一個(gè)人

var person = {
    "Name": "Bob",
    "Age": 32,
    "Company": "IBM",
    "Engineer": true
}

// 獲取這個(gè)人的信息

var personAge = person.Age;

// 描述幾個(gè)人

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的公司名稱(chēng)

var johnsCompany = members[1].Company;

// 描述一次會(huì)議

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
        }
    ]
}

// 讀取參會(huì)者Henry是否工程師

var henryIsAnEngineer = conference.Members[2].Engineer;

  • 值為字符串的時(shí)候焦辅,是雙引號(hào)博杖,不是單引號(hào)
  • 集合中若有多個(gè)子項(xiàng)椿胯,最后一項(xiàng)不能加逗號(hào)
  • 鍵名一定要加雙引號(hào)
  • 可以在線(xiàn)檢測(cè)JSON格式是否符合規(guī)范 bejson

什么是JSONP筷登?

先說(shuō)說(shuō)為什么要用JSONP

  • 一個(gè)眾所周知的問(wèn)題,Ajax直接請(qǐng)求普通文件存在跨域無(wú)權(quán)限訪問(wèn)的問(wèn)題哩盲;
  • 不過(guò)我們又發(fā)現(xiàn)前方,Web頁(yè)面上調(diào)用js文件時(shí)則不受是否跨域的影響(不僅如此,我們還發(fā)現(xiàn)凡是擁有"src"這個(gè)屬性的標(biāo)簽都擁有跨域的能力廉油,比如script惠险、imgiframe)抒线;
  • 這樣子解決方案就呼之欲出了班巩,web客戶(hù)端通過(guò)與調(diào)用腳本一模一樣的方式,來(lái)調(diào)用跨域服務(wù)器上動(dòng)態(tài)生成的js格式文件(一般以JSON為后綴)嘶炭,顯而易見(jiàn)抱慌,服務(wù)器之所以要?jiǎng)討B(tài)生成JSON文件,目的就在于把客戶(hù)端需要的數(shù)據(jù)裝入進(jìn)去眨猎。
  • 為了便于客戶(hù)端使用數(shù)據(jù)抑进,逐漸形成了一種非正式傳輸協(xié)議,人們把它稱(chēng)作JSONP睡陪,該協(xié)議的一個(gè)要點(diǎn)就是允許用戶(hù)傳遞一個(gè)callback參數(shù)給服務(wù)端寺渗,然后服務(wù)端返回?cái)?shù)據(jù)時(shí)會(huì)將這個(gè)callback參數(shù)作為函數(shù)名來(lái)包裹住JSON數(shù)據(jù)匿情,這樣客戶(hù)端就可以隨意定制自己的函數(shù)來(lái)自動(dòng)處理返回?cái)?shù)據(jù)了。
    如果對(duì)于callback參數(shù)如何使用還有些模糊的話(huà)信殊,我們后面會(huì)有具體的實(shí)例來(lái)講解炬称。

1、我們知道涡拘,哪怕跨域js文件中的代碼(當(dāng)然指符合web腳本安全策略的)转砖,web頁(yè)面也是可以無(wú)條件執(zhí)行的。
在命令行下執(zhí)行 node server1.js, server1.js內(nèi)容為:

var http = require('http');  
http.createServer(function (req, res) {  
  res.writeHead(200, {'Content-Type': 'application/json'});  
    res.end('alert("我是遠(yuǎn)程文件")');
}).listen(8080);  
console.log('Server running on port 8080.');

在瀏覽器中訪問(wèn)"http://localhost:8080"
jsonp1.html script src指向http://localhost:8080鲸伴,具體代碼如下

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8" />
  <title></title>
  <script src="http://localhost:8080"></script>
 </head>
 <body>
 </body>
</html>

毫無(wú)疑問(wèn)府蔗,頁(yè)面將會(huì)彈出一個(gè)提示窗體,顯示跨域調(diào)用成功汞窗。

2姓赤、現(xiàn)在我們?cè)趈sonp2.html頁(yè)面定義一個(gè)函數(shù),然后在server2.js中傳入數(shù)據(jù)進(jìn)行調(diào)用仲吏。
jsonp2.html內(nèi)容

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8" />
  <title></title>
  <script>
   var localHandler = function(data) {
    alert('我是本地函數(shù)不铆,可以被跨域的remote.js文件調(diào)用,遠(yuǎn)程js帶來(lái)的數(shù)據(jù)是:' + data.result);
   };
  </script>
  <script src="http://localhost:8080"></script>
 </head>
 <body>
 </body>
</html>

server2.js 內(nèi)容

var http = require('http');  
http.createServer(function (req, res) {  
  res.writeHead(200, {'Content-Type': 'application/json'});  
   res.end('localHandler({"result":"我是遠(yuǎn)程js帶來(lái)的數(shù)據(jù)"})');
}).listen(8080);  

console.log('Server running on port 8080.');

運(yùn)行之后查看結(jié)果裹唆,頁(yè)面成功彈出提示窗口誓斥,顯示本地函數(shù)被跨域的遠(yuǎn)程js調(diào)用成功,并且還接收到了遠(yuǎn)程js帶來(lái)的數(shù)據(jù)许帐。很欣喜劳坑,跨域遠(yuǎn)程獲取數(shù)據(jù)的目的基本實(shí)現(xiàn)了,但是又一個(gè)問(wèn)題出現(xiàn)了成畦,我怎么讓遠(yuǎn)程js知道它應(yīng)該調(diào)用的本地函數(shù)叫什么名字呢距芬?畢竟是jsonp的服務(wù)者都要面對(duì)很多服務(wù)對(duì)象,而這些服務(wù)對(duì)象各自的本地函數(shù)都不相同把省框仔?我們接著往下看。

3拄养、聰明的開(kāi)發(fā)者很容易想到离斩,只要服務(wù)端提供的js腳本是動(dòng)態(tài)生成的就行了唄,這樣調(diào)用者可以傳一個(gè)參數(shù)過(guò)去告訴服務(wù)端“我想要一段調(diào)用XXX函數(shù)的js代碼瘪匿,請(qǐng)你返回給我”跛梗,于是服務(wù)器就可以按照客戶(hù)端的需求來(lái)生成js腳本并響應(yīng)了。
看jsonp3.html頁(yè)面的代碼:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8" />
  <title></title>
  <script type="text/javascript">
   // 得到航班信息查詢(xún)結(jié)果后的回調(diào)函數(shù)
   var flightHandler = function(data) {
    alert('你查詢(xún)的航班結(jié)果是:票價(jià) ' + data.price + ' 元柿顶,' + '余票 ' + data.tickets + ' 張茄袖。');
   };
   // 提供jsonp服務(wù)的url地址(不管是什么類(lèi)型的地址,最終生成的返回值都是一段javascript代碼)
   var url = "http://localhost:8080?callback=flightHandler";
   // 創(chuàng)建script標(biāo)簽嘁锯,設(shè)置其屬性
   var script = document.createElement('script');
   script.setAttribute('src', url);
   // 把script標(biāo)簽加入head宪祥,此時(shí)調(diào)用開(kāi)始
   document.getElementsByTagName('head')[0].appendChild(script);
  </script>
 </head>
 <body>
 </body>
</html>

這次的代碼變化比較大聂薪,不再直接把遠(yuǎn)程js文件寫(xiě)死,而是編碼實(shí)現(xiàn)動(dòng)態(tài)查詢(xún)蝗羊,而這也正是jsonp客戶(hù)端實(shí)現(xiàn)的核心部分藏澳,本例中的重點(diǎn)也就在于如何完成jsonp調(diào)用的全過(guò)程。
我們看到調(diào)用的url中傳遞了一個(gè)callback參數(shù)則告訴服務(wù)器耀找,我的本地回調(diào)函數(shù)叫做flightHandler翔悠,所以請(qǐng)把查詢(xún)結(jié)果傳入這個(gè)函數(shù)中進(jìn)行調(diào)用。
OK野芒,服務(wù)器很聰明蓄愁,這個(gè)叫做server3.js的頁(yè)面生成了一段這樣的代碼提供給jsonp3.html。server3.js的頁(yè)面代碼:

var http = require('http');  
var URL = require('url');

http.createServer(function (req, res) {  
  res.writeHead(200, {'Content-Type': 'application/json'});  
  var params = URL.parse(req.url, true).query;
   res.end(params.callback+'({"code": "CA1998","price": 1780,"tickets": 5})');
 }).listen(8080);  

console.log('Server running on port 8080.');

我們看到狞悲,傳遞給flightHandler函數(shù)的是一個(gè)json撮抓,它描述了航班的基本信息。運(yùn)行一下頁(yè)面摇锋,成功彈出提示窗口丹拯,jsonp的執(zhí)行全過(guò)程順利完成!

4荸恕、到這里為止的話(huà)乖酬,相信你已經(jīng)能夠理解jsonp的客戶(hù)端實(shí)現(xiàn)原理了吧?剩下的就是如何把代碼封裝一下融求,以便于與用戶(hù)界面交互咬像,從而實(shí)現(xiàn)多次和重復(fù)調(diào)用。
什么双肤?你用的是jQuery施掏,想知道jQuery如何實(shí)現(xiàn)jsonp調(diào)用?好吧茅糜,那我就好人做到底,再給你一段jQuery使用jsonp的代碼(我們依然沿用上面那個(gè)航班信息查詢(xún)的例子素挽,假定返回jsonp結(jié)果不變):

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8" />
  <title></title>
  <script src="http://apps.bdimg.com/libs/jquery/1.6.4/jquery.js"></script>
  <script type="text/javascript">
   $.ajax({
    type: "get",
    async: false,
    url: "http://localhost:8080",
    dataType: "jsonp",
    jsonp: "callback", //傳遞給請(qǐng)求處理程序或頁(yè)面的蔑赘,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(一般默認(rèn)為:callback)
    success: function(json) {
     alert('您查詢(xún)到航班信息:票價(jià): ' + json.price + ' 元,余票: ' + json.tickets + ' 張预明。');
    },
    error: function() {
     alert('fail');
    }
   });
  </script>
 </head>
 <body>
 </body>
</html>

是不是有點(diǎn)奇怪缩赛?為什么我這次沒(méi)有寫(xiě)flightHandler這個(gè)函數(shù)呢?而且竟然也運(yùn)行成功了撰糠!哈哈酥馍,這就是jQuery的功勞了,jquery在處理jsonp類(lèi)型的ajax時(shí)(還是忍不住吐槽阅酪,雖然jquery也把jsonp歸入了ajax旨袒,但其實(shí)它們真的不是一回事兒)汁针,自動(dòng)幫你生成回調(diào)函數(shù)并把數(shù)據(jù)取出來(lái)供success屬性方法來(lái)調(diào)用,是不是很爽呀砚尽?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末施无,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子必孤,更是在濱河造成了極大的恐慌猾骡,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敷搪,死亡現(xiàn)場(chǎng)離奇詭異兴想,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赡勘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)襟企,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人狮含,你說(shuō)我怎么就攤上這事顽悼。” “怎么了几迄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵蔚龙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我映胁,道長(zhǎng)木羹,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任解孙,我火速辦了婚禮坑填,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘弛姜。我一直安慰自己脐瑰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布廷臼。 她就那樣靜靜地躺著苍在,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荠商。 梳的紋絲不亂的頭發(fā)上寂恬,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音莱没,去河邊找鬼初肉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛饰躲,可吹牛的內(nèi)容都是我干的牙咏。 我是一名探鬼主播臼隔,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼眠寿!你這毒婦竟也來(lái)了躬翁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盯拱,失蹤者是張志新(化名)和其女友劉穎盒发,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體狡逢,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宁舰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奢浑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛮艰。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖雀彼,靈堂內(nèi)的尸體忽然破棺而出壤蚜,到底是詐尸還是另有隱情,我是刑警寧澤徊哑,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布袜刷,位于F島的核電站,受9級(jí)特大地震影響莺丑,放射性物質(zhì)發(fā)生泄漏著蟹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一梢莽、第九天 我趴在偏房一處隱蔽的房頂上張望萧豆。 院中可真熱鬧,春花似錦昏名、人聲如沸涮雷。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)份殿。三九已至,卻和暖如春嗽交,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背颂斜。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工夫壁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沃疮。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓盒让,卻偏偏與公主長(zhǎng)得像梅肤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子邑茄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容