就最近寫了很多Ajax的東西,接觸到Ajax的第一件事就是HttpXML.send()之後,伺服器要回傳什麼資料,一般都是responseText或responseXML,也就是說,1. 回傳純文字;2. 回傳XML,純文字難以分析處理(要跑DOM時),XML在伺服器端要花很多力氣去「組合」出XML資料,然後用戶端再寫很多Code去分析處理,這是很沒效率的。
所以就快快把JSON學一學吧!
JSON概念
進入JSON前,請先看我這篇「第二篇:簡單介紹JavaScript內建物件」Array物件第一段「Array宣告」的地方,宣告一個Javascript Array物件,基本上是兩種語法:
1 | // 正式宣告 |
2 | var team1 = new Array( 'Bruce' , 'Sherry' , 'Happy' ); |
3 | // 整合宣告 |
4 | var team2 = [ 'Bruce' , 'Sherry' , 'Happy' ]; |
5 | alert(team1[0]); // Bruce |
6 | alert(team2[2]); // Happy |
一個比較正式,一個是比較簡寫,通常Javascript寫久了,會採用第二種方式來宣告Array。
再來看Javascript物件的宣告,基本上也是兩種:
01 | // 正式宣告 |
02 | var Bruce = new Object(); |
03 | Bruce.name = 'King Kong' ; |
04 | Bruce.age = 18; |
05 | Bruce.sex = 'male' ; |
06 | alert(Bruce.age); // 18 |
07 |
08 | // 整合宣告 |
09 | var Bruce = { |
10 | 'name' : 'King Kong' , |
11 | 'age' : 18, |
12 | 'sex' : 'male' |
13 | } |
14 | alert(Bruce.name); // King Kong |
15 | alert(Bruce[name]); // King Kong |
一樣,久了也是會選第二種來寫,再來我們看看Javascript的「Array + Object」的宣告:
01 | // 宣告一個familys Array,裡面包含兩個Object |
02 | var familys = [ |
03 | { 'name' : 'Bruce' , |
04 | 'age' : 18, |
05 | 'sex' : 'male' }, |
06 | { 'name' : 'Sherry' , |
07 | 'age' : 16, |
08 | 'sex' : 'famale' } |
09 | ]; |
10 | alert(family[0].name); // Bruce |
11 | alert(family[1].sex); // famale |
到這裡你已經會了JSON的80%以上了,JSON (JavaScript Object Notation)已經說明的很清楚了,它是一個JavaScript的子集,它利用Object與Array來表示資料,讓資料很容易的可以交換使用。
JSON寫法
我們先來看完整的JSON寫法:
01 | { |
02 | 'familys' = [ |
03 | { 'name' : 'Bruce' , |
04 | 'age' : 18, |
05 | 'sex' : 'male' }, |
06 | { 'name' : 'Sherry' , |
07 | 'age' : 16, |
08 | 'sex' : 'famale' } |
09 | ] |
10 | } |
JSON會建構出兩種結構:(1)「"名稱" : 值」的集合;(2)Array。
JSON的細節
比對上面範例,你會發現一點也不難。JSON Object:
- 以"{"開始,以"}"結尾
- 每個名稱後跟著一個":"
- 每對"名稱:值"之間用","分隔
1 | { // 以"{"開始 |
2 | 'name' : 'Bruce' , // 每個名稱後跟著一個":" |
3 | 'age' : 18, // 每對"名稱:值"之間用","分隔 |
4 | 'sex' : 'male' |
5 | } // 以"}"結尾 |
JSON Array:
- 以"["開始,以"]"結尾
- 值之間使用","
01 | { |
02 | // familys為一維陣列,陣列裡包含兩筆物件資料 |
03 | 'familys' = [ // 以"["開始 |
04 | { 'name' : 'Bruce' , |
05 | 'age' : 18, |
06 | 'sex' : 'male' }, // 值之間使用"," |
07 | { 'name' : 'Sherry' , |
08 | 'age' : 16, |
09 | 'sex' : 'famale' } |
10 | ] // 以"]"結尾 |
11 | } |
JSON Value:
- 值本身可以是String、Number、true、false、null、Object、Array;
JSON String:
- 由雙引號包圍的任意Unicode字元集合。可以使用"反斜線(\)"來轉義。
1 | { |
2 | "details" : "這是JSON的值. \n 此格式比XML合適Ajax交換資料使用." |
3 | } |
JSON Number:
- 與一般數值相同,除8 / 16進制外。
JSON的使用
那JSON要如何使用呢?原生的JSON格式資料,目前在IE7以上及MF 3以上,已經內建解析JSON格式的能力,但在相容性及網路上的不確定性(其他瀏覽器),建議在有需要使用JSON格式的頁面引用json2.js,依官方說法,請不要在使用json.js這個版本的Script了。
我們有一JSON格式的String:
1 | var jsonData = "{ 'familys' =[{ 'name' : 'Bruce' , 'age' : 18, 'sex' : 'male' }, |
2 | { 'name' : 'Sherry' , 'age' : 16, 'sex' : 'famale' }]}" |
方法一:使用eval()
這個方法會引發安全性問題,我就不介紹了。
方法二:使用json2.js (IE7以上及MF 3以上可以不引用)
先在網頁中引用json2.js,然後使用json2所提供的parse方法:
1 | var jsonData = "{ 'familys' =[{ 'name' : 'Bruce' , 'age' : 18, 'sex' : 'male' }, |
2 | { 'name' : 'Sherry' , 'age' : 16, 'sex' : 'famale' }]}" |
3 |
4 | var jsonObj = JSON.parse(jsonData); // 將JSON格式資料轉為物件 |
5 |
6 | alert(jsonObj.familys[0].name); // Bruce |
7 | alert(jsonObj.familys[1].age); // 16 |
這樣之後,我們就能在Ajax函式將伺服器傳回的JSON格式做解析:
1 | // ... |
2 | if (xmlHttp.readyState == 4 && xmlHttp.status == 200){ |
3 | var jsonObj = JSON.parse(xmlHttp.responseText); |
4 | // ... |
5 | } |
使用了JSON來交換資料後,你會發現相關Ajax的程式碼變簡單了,例如:
01 | // 原始Ajax函數 |
02 | function Do(xmlHttp) { |
03 | if (xmlHttp.readyState == 4 && xmlHttp.status == 200){ |
04 | var familys = xmlHttp.responseXML.getElementsByTagName( 'familys' ); |
05 | for ( var i = 0; i < familys.length; i++) { |
06 | var name = familys.getElementsByTagName( 'name' )[0].firstChild.nodeValue; |
07 | var age = familys.getElementsByTagName( 'age' )[0].firstChild.nodeValue; |
08 | var sex = familys.getElementsByTagName( 'sex' )[0].firstChild.nodeValue; |
09 | } |
10 | } |
11 | } |
12 |
13 | // 使用JSON後的Ajax函數 |
14 | function Do(xmlHttp) { |
15 | if (xmlHttp.readyState == 4 && xmlHttp.status == 200){ |
16 | var jsonObj = JSON.parse(xmlHttp.responseText); |
17 | var name = jsonObj.familys[0].name; |
18 | var age = jsonObj.familys[0].age; |
19 | var sex = jsonObj.familys[0].sex; |
20 | } |
21 | } |
不只有變簡單,而且程式的撰寫更直覺。另外,你也可以把Object轉為JSON:
01 | // 宣告一個familys Array,裡面包含兩個Object |
02 | var familys = [ |
03 | { 'name' : 'Bruce' , |
04 | 'age' : 18, |
05 | 'sex' : 'male' }, |
06 | { 'name' : 'Sherry' , |
07 | 'age' : 16, |
08 | 'sex' : 'famale' } |
09 | ]; |
10 |
11 | var jsonData = JSON.stringify(familys); |
更快速的是使用jQuery的$getJSON,但這超出了JSON的討論了。以上是接收解析JSON,那如果我要傳送JSON給伺服器呢?也簡單:
1 | var xhr = request(); // 建立XHR物件 |
2 | xhr.onreadystatechange = handler; |
3 | xhr.open( 'POST' ,URL); |
4 | xhr.setRequestHeader( 'Content-Type' , 'application/json' ); // 這裡是重點 |
5 | xhr.send(json); |
記得使用'application/json'來傳送即可,但一般伺服器端是看不懂JSON,不過沒關係,在JSON官網最下方或上網找一下,已經有很多高手分享出來可以在伺服器解析JSON的元件或Source Code,讓JSON資料傳送到伺服器後,依然方便好用。
使用JSONP進行跨站請求
這個主題比較生硬,如果你不會使用到跨網站請求,可以先跳過。一般而言,在網站中是不太充許你去存取其他網站的內容,但不是百分百,例如iframe或img就是很好的例子,但其他HTML、Javascript就都不太能做這種事,例如XMLHttpRequest,這是一種保護。但現今網頁已經很少能不去存取其他網站,例如掛個「噗浪」「fb」…,但偏偏XMLHttpRequest不充許跨網站去存取。
後來有人發展出了JSONP(JSON with Padding),JSONP利用Javascript的callback機制,繞過Browser的安全限制,關鍵在動態載入<script src="...">,利用src來載入外部JSON資料或Javascript function到網頁中。
我們先來看動態建立Script
1 | var Script = document.createElement( 'script' ); |
2 | Script.type = 'text/javascript' ; |
3 | Script.src = 'http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.4.4.min.js' ; |
4 | document.getElementByTagName( 'head' ).[0].appendChild(Script); |
這相當於在head最下面新增一段script tag:
1 | <script type= "text/javascript" src= "http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.4.4.min.js" ></script> |
這差不多就是JSONP的基礎了,透過動態建立script及Javascript callback,來載入跨網站JSON資料。
最後我們來看整個JSONP的運作流程示意程式碼,注意程式的流程,Step 1在Client--> Step 2在Server--> Step 3 回到Client。
Client端:*.html
01 | // 使用jQuery |
02 |
03 | // Step 1:送出JSONP請求, |
04 | $( function (){ |
05 | $( '#send' ).click( function (){ |
06 | // 最後必須是 &callback=funcion 或 &jsoncallback=function 結尾 |
08 |
09 | $.ajax({ |
10 | type : 'GET' , |
11 | dataType : 'jsonp' , // 記得是jsonp |
12 | url : URL, |
13 | error : function (xhr, error){ alert( 'Ajax request error.' );} |
14 | }) |
15 | }) |
16 | }); |
17 |
18 | // Step 3:收到伺服器回應後(response.write(jsonp)),執行的callback的function |
19 |
20 | function dosomething(jsonData){ |
21 | // jsonData會取得Server傳回{...json data ...} |
22 | alert(jsonData.name); |
23 | alert(jsonData.age); |
24 | alert(jsonData.sex); |
25 | } |
在建立非同請求時,在網址最後加上「&callback=函數名稱」或「&jsoncallback=函數名稱」,就可以取得其他網域的資料並執行後續callback的函數。
Server端 *.aspx
01 | ' Step 2:進行相關處理 |
02 |
03 | '接收到的id & name處理... |
04 |
05 | ' 以下是重點,組合出function及json資料,然後回傳 |
06 | Dim jsonp AS String = |
07 | ' dosomething是 function name |
08 | ' {...} 是json data |
09 | jsonp = "dosomething({ _ |
10 | ' ... json data ... _ |
11 | })" |
12 |
13 | Response.Write(jsonp) |
Reference:
- Javascript
- http://www.json.org/json-zh.html (官方網站,一定要看)
- https://github.com/douglascrockford/JSON-js (請下載json2.js使用)
- http://blog.roodo.com/syshen/archives/1410294.html (JSON介紹)
- http://pulipuli.blogspot.com/2010/08/ajaxjavascriptjsonp.html (Ajax & JSON投影片做得好)
- http://happytemplate.blogspot.com/2007/11/jsonp.html (JSONP例子簡單)
- http://herolin.twbbs.org/?s=jsonp
- http://caterpillar.onlyfun.net/Gossip/JavaScript/index.html (很多Javascript資料)
- http://www.pozzware.com (可以下載到Visual Basic 2008解析JSON的Source Code,可自行編譯為*.DLL,但註冊及成為正式使用者需要一些日子,我約二~三週後才成為RegisteredUser,然後才下載到PW.JSON Library)
沒有留言:
張貼留言