JSON和JSONP的區別


先前的概念中對JSON還是比較熟悉JSONP不是特別的清楚整理完相關知識發現才豁然開朗簡單的說JSON是一種數據交換格式而JSONP是 一種非官方跨域數據交互協議。JSON暗號”,JSONP則是接頭方式一個是描述信息的格式一個是信息傳遞雙方約定的方法

什么是JSON

JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式 易於人閱讀和編寫同時也易於機器解析和生成 它基於JavaScript Programming LanguageStandard ECMA-262 3rd Edition – December 1999的一個子集 JSON采用完全獨立於語言的文本格式但是也使用了類似於C語言家族的習慣包括C, C++, C#, Java, JavaScript, Perl, Python)。 這些特性使JSON成為理想的數據交換語言

JSON建構於兩種結構

  • 名稱/對的集合(A collection of name/value pairs)。不同的語言中它被理解為對象(object),紀錄(record),結構(struct),字典(dictionary),哈希表(hash table),有鍵列表(keyed list),或者關聯數組 (associative array)。
  • 值的有序列表(An ordered list of values)。在大部分語言中它被理解為數組(array)。

這些都是常見的數據結構事實上大部分現代計算機語言都以某種形式支持它們這使得一種數據格式在同樣基於這些結構的編程語言之間交換成為可能

JSON具有以下這些形式

對象是一個無序的“‘名稱/集合一個對象以“{”(左括號開始,“}”(右括號結束每個名稱后跟一個“:”(冒號);“‘名稱/之間使用“,”(逗號分隔

數組是值(value)的有序集合一個數組以“[”(左中括號開始,“]”(右中括號結束值之間使用“,”(逗號分隔

value可以是雙引號括起來的字符串string)、數值(number)、truefalse、 null對象(object)或者數組(array)。這些結構可以嵌套

字符串string是由雙引號包圍的任意數量Unicode字符的集合使用反斜線轉義一個字符(character)即一個單獨的字符串(character string)。

字符串stringC或者Java的字符串非常相似

數值number也與C或者Java的數值非常相似除去未曾使用的八進制與十六進制格式除去一些編碼細節

空白可以加入到任何符號之間 以下描述了完整的語言

JSON的優點

  1. 基於純文本跨平台傳遞極其簡單
  2. Javascript原生支持后台語言幾乎全部支持
  3. 輕量級數據格式占用字符數量極少特別適合互聯網傳遞
  4. 可讀性較強雖然比不上XML那么一目了然但在合理的依次縮進之后還是很容易識別的
  5. 容易編寫和解析當然前提是你要知道數據結構
// 描述一個人
 
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;

什么是JSONP?

JSONP(JSON with Padding)是資料格式 JSON 的一種使用模式”,可以讓網頁從別的網域要資料由於同源策略一般來說位於 server1.example.com 的網頁無法與不是 server1.example.com 的服務器溝通而 HTML 的 <script> 元素是一個例外利用<script> 元素的這個開放策略網頁可以得到從其他來源動態產生的 JSON 資料而這種使用模式就是所謂的 JSONP。JSONP 抓到的資料並不是 JSON,而是任意的 JavaScript,JavaScript 直譯器執行而不是用 JSON 解析器解析

為了理解這種模式的原理先想像有一個回傳 JSON 文件的 URL,JavaScript 程式可以用 XMLHttpRequest 跟這個 URL 要資料假設我們的 URLhttp://server2.example.com/RetrieveUser?UserId=xxx 。假設小明的 UserId1823,且當瀏覽器透過 URL 傳小明的 UserId,也就是抓取http://server2.example.com/RetrieveUser?UserId=1823 ,得到

{"Name": "小明", "Id" : 1823, "Rank": 7}

這個 JSON 資料可能是依據傳過去 URL 的查詢參數動態產生的

這個時候把 <script> 元素的 src 屬性設成一個回傳 JSONURL 是可以想像的這也代表從 HTML 頁面透過 script 元素抓取 JSON 是可能的

然而一份 JSON 文件並不是一個 JavaScript 程式為了讓瀏覽器可以在 <script> 元素執行srcURL 回傳的必須是可執行的 JavaScript。JSONP 的使用模式里URL 回傳的是由函數呼叫包起來的動態生成 JSON,這就是JSONP填充(padding)”或是前輟(prefix)”的由來

慣例上瀏覽器提供回調函數的名稱當作送至服務器的請求中命名查詢參數的一部份例如

<script type="text/javascript" src="http://server2.example.com/RetrieveUser?UserId=1823&jsonp=parseResponse"> </script>

服務器會在傳給瀏覽器前將 JSON 數據填充到回調函數(parseResponse)瀏覽器得到的回應已不是單純的資料敘述而是一個腳本在本例中瀏覽器得到的是

parseResponse({"Name": "Cheeso", "Id" : 1823, "Rank": 7})

雖然這個填充前輟)“通常是瀏覽器執行背景中定義的某個回調函數它也可以是變量賦值、if 敘述或者是其他 JavaScript 敘述。JSONP 要求也就是使用 JSONP 模式的請求的回應不是 JSON 也不被當作 JSON 解析——回傳內容可以是任意的運算式甚至不需要有任何的 JSON,不過慣例上填充部份還是會觸發函數調用的一小段 JavaScript 片段而這個函數呼叫是作用在 JSON 格式的資料上的

另一種說法—典型的 JSONP 就是把既有的 JSON API 用函數呼叫包起來以達到跨域存取的解法為了要啟動一個 JSONP 呼叫或者說使用這個模式),你需要一個 script 元素因此瀏覽器必須為每一個 JSONP 要求加或是重用一個新的有所需 src 值的 <script> 元素到 HTML DOM 里—或者說是注入這個元素瀏覽器執行該元素抓取 src 里的 URL,並執行回傳的 JSON。也因為這樣,JSON 被稱作是一種讓使用者利用 script 元素注入的方式繞開同源策略的方法

使用遠端網站的 script 標簽會讓遠端網站得以注入任何的內容至網站里如果遠端的網站有 JavaScript 注入漏洞原來的網站也會受到影響.現在有一個正在進行計划在定義所謂的 JSON-P 嚴格安全子集使瀏覽器可以對 MIME 類別是“application/json-p”請求做強制處理如果回應不能被解析為嚴格的 JSON-P,瀏覽器可以丟出一個錯誤或忽略整個回應

粗略的 JSONP 部署很容易受到跨網站的偽造要求(CSRF/XSRF)的攻擊因為 HTML <script> 標簽在瀏覽器里不遵守同源策略惡意網頁可以要求並取得屬於其他網站的 JSON 資料當使用者正登入那個其他網站時上述狀況使得該惡意網站得以在惡意網站的環境下操作該 JSON 資料可能泄漏使用者的密碼或是其他敏感資料

只有在該 JSON 資料含有不該泄漏給第三方的隱密資料且服務器僅靠瀏覽器的同源策略阻擋不正常要求的時候這才會是問題若服務器自己決定要求的專有性並只在要求正常的情況下輸出資料則沒有問題只靠 Cookie 並不夠決定要求是合法的這很容易受到跨網站的偽造要求攻擊

JSONP的客戶端具體實現

下面來說明一下jsonp在客戶端的實現

1、我們知道哪怕跨域js文件中的代碼當然指符合web腳本安全策略的),web頁面也是可以無條件執行的

遠程服務器remoteserver.com根目錄下有個remote.js文件代碼如下

alert('我是遠程文件')

本地服務器localserver.com下有個jsonp.html頁面代碼如下

<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頁面代碼如下

<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的服務者都要面對很多服務對象而這些服務對象各自的本地函數都不相同啊我們接着往下看

聰明的開發者很容易想到只要服務端提供的js腳本是動態生成的就行了唄這樣調用者可以傳一個參數過去告訴服務端我想要一段調用XXX函數的js代碼請你返回給我”,於是服務器就可以按照客戶端的需求來生成js腳本並響應了

jsonp.html頁面的代碼

<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
});

我們看到傳遞給flightHandler函數的是一個json,它描述了航班的基本信息運行一下頁面成功彈出提示窗口,jsonp的執行全過程順利完成

4、到這里為止的話相信你已經能夠理解jsonp的客戶端實現原理了吧剩下的就是如何把代碼封裝一下以便於與用戶界面交互從而實現多次和重復調用

jQueryJSONP的實現

我們依然沿用上面那個航班信息查詢的例子假定返回jsonp結果不變

<!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>Untitled Page</title>
<script type="text/javascript" src=jquery.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
 
$.ajax({
type: "get",
async: false,
url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",//傳遞給請求處理程序或頁面的,用以獲得jsonp回調函數名的參數名(一般默認為:callback)
jsonpCallback:"flightHandler",//自定義的jsonp回調函數名稱,默認為jQuery自動生成的隨機函數名,也可以寫"?",jQuery會自動為你處理數據
success: function(json){
alert('您查詢到航班信息:票價: ' + json.price + ' 元,余票: ' + json.tickets + ' 張。');
},
error: function(){
alert('fail');
}
});
});
</script>
</head>
<body>
</body>
</html>

為什么我這次沒有寫flightHandler這個函數呢而且竟然也運行成功了這就是jQuery的功勞了,jquery在處理jsonp類型的ajax時自動幫你生成回調函數並把數據取出來供success屬性方法來調用

ajaxjsonp的異同

  1. ajaxjsonp這兩種技術在調用方式上看起來很像目的也一樣都是請求一個url,然后把服務器返回的數據進行處理因此jqueryext等框架都把jsonp作為ajax的一種形式進行了封裝
  2. ajaxjsonp其實本質上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內容jsonp的核心則是動態添加<script>標簽來調用服務器提供的js腳本
  3. 所以說其實ajaxjsonp的區別不在於是否跨域,ajax通過服務端代理一樣可以實現跨域,jsonp本身也不排斥同域的數據的獲取
  4. 還有就是,jsonp是一種方式或者說非強制性協議如同ajax一樣它也不一定非要用json格式來傳遞數據如果你願意字符串都行只不過這樣不利於用jsonp提供公開服務

總而言之,jsonp不是ajax的一個特例哪怕jquery等巨頭把jsonp封裝進了ajax,也不能改變着一點


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM