1. 程式人生 > >JSON與jsonp

JSON與jsonp

JSON 語法規則

JSON 語法是 JavaScript 物件表示法語法的子集。

  • 資料在名稱/值對中
  • 資料由逗號分隔
  • 花括號儲存物件
  • 方括號儲存陣列

JSON 名稱/值對

JSON 資料的書寫格式是:名稱/值對。

名稱/值對包括欄位名稱(在雙引號中),後面寫一個冒號,然後是值:

"firstName" : "John"

這很容易理解,等價於這條 JavaScript 語句:

firstName = "John"

JSON 值

JSON 值可以是:

  • 數字(整數或浮點數)
  • 字串(在雙引號中)
  • 邏輯值(true 或 false)
  • 陣列(在方括號中)
  • 物件(在花括號中)
  • null

JSON 物件

JSON 物件在花括號中書寫:

物件可以包含多個名稱/值對:

{ "firstName":"John" , "lastName":"Doe" }

這一點也容易理解,與這條 JavaScript 語句等價:

firstName = "John"
lastName = "Doe"

JSON 陣列

JSON 陣列在方括號中書寫:

陣列可包含多個物件:

{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]
}

在上面的例子中,物件 "employees" 是包含三個物件的陣列。每個物件代表一條關於某人(有姓和名)的記錄。

JSON 使用 JavaScript 語法

因為 JSON 使用 JavaScript 語法,所以無需額外的軟體就能處理 JavaScript 中的 JSON。

通過 JavaScript,您可以建立一個物件陣列,並像這樣進行賦值:

例子

var employees = [
{ "firstName":"Bill" , "lastName":"Gates" },
{ "firstName":"George" , "lastName":"Bush" },
{ "firstName":"Thomas" , "lastName": "Carter" }
];

可以像這樣訪問 JavaScript 物件陣列中的第一項:

employees[0].lastName;

返回的內容是:

Gates

JSONP的客戶端具體實現:

不管jQuery也好,extjs也罷,又或者是其他支援jsonp的框架,他們幕後所做的工作都是一樣的,下面我來循序漸進的說明一下jsonp在客戶端的實現:

1、我們知道,哪怕跨域js檔案中的程式碼(當然指符合web指令碼安全策略的),web頁面也是可以無條件執行的。

遠端伺服器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、現在我們在jsonp.html頁面定義一個函式,然後在遠端remote.js中傳入資料進行呼叫。

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('我是本地函式,可以被跨域的remote.js檔案呼叫,遠端js帶來的資料是:' + data.result);
    };
    </script>
    <script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
</head>
<body>

</body>
</html>
複製程式碼

remote.js檔案程式碼如下:

localHandler({"result":"我是遠端js帶來的資料"});

執行之後檢視結果,頁面成功彈出提示視窗,顯示本地函式被跨域的遠端js呼叫成功,並且還接收到了遠端js帶來的資料。很欣喜,跨域遠端獲取資料的目的基本實現了,但是又一個問題出現了,我怎麼讓遠端js知道它應該呼叫的本地函式叫什麼名字呢?畢竟是jsonp的服務者都要面對很多服務物件,而這些服務物件各自的本地函式都不相同啊?我們接著往下看。

3、聰明的開發者很容易想到,只要服務端提供的js指令碼是動態生成的就行了唄,這樣呼叫者可以傳一個引數過去告訴服務端“我想要一段呼叫XXX函式的js程式碼,請你返回給我”,於是伺服器就可以按照客戶端的需求來生成js指令碼並響應了。

看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 flightHandler = function(data){
        alert('你查詢的航班結果是:票價 ' + data.price + ' 元,' + '餘票 ' + data.tickets + ' 張。');
    };
    // 提供jsonp服務的url地址(不管是什麼型別的地址,最終生成的返回值都是一段javascript程式碼)
    var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
    // 建立script標籤,設定其屬性
    var script = document.createElement('script');
    script.setAttribute('src', url);
    // 把script標籤加入head,此時呼叫開始
    document.getElementsByTagName('head')[0].appendChild(script); 
    </script>
</head>
<body>

</body>
</html>
複製程式碼

這次的程式碼變化比較大,不再直接把遠端js檔案寫死,而是編碼實現動態查詢,而這也正是jsonp客戶端實現的核心部分,本例中的重點也就在於如何完成jsonp呼叫的全過程。

我們看到呼叫的url中傳遞了一個code引數,告訴伺服器我要查的是CA1998次航班的資訊,而callback引數則告訴伺服器,我的本地回撥函式叫做flightHandler,所以請把查詢結果傳入這個函式中進行呼叫。

OK,伺服器很聰明,這個叫做flightResult.aspx的頁面生成了一段這樣的程式碼提供給jsonp.html:

flightHandler({
    "code": "CA1998",
    "price": 1780,
    "tickets": 5
});