有關json與jsonp的區別(json才是目的,jsonp只是手段)介紹如下所示:
一言以蔽之,json返回的是一串資料;而jsonp返回的是指令碼代碼(包含一個函數調用);
JSON其實就是JavaScript中的一個對象,跟var obj={}在質上完全一樣,只是在量上可以無限擴充。簡單地講,json其實就是JavaScript中的對象(Object)和數組(Array,其實也是對象)這倆好基友在那兒你嵌我我嵌你地套上n多層,以此類比出許多複雜的資料結構。
json易於人閱讀和編寫,也易於機器解析和產生,相對網路傳輸速率較高,功能型網站前後端往往要頻繁大量交換資料,而json憑藉其強大的表現力和高顏值漸漸地成為理想的前後端資料交換語言。那xml前輩呢,我覺得應該會像微軟的xp那樣功成身退。
同源(不懂同源策略的童鞋請自行百度)下的前後端資料交換格式確定使用json了,那麼問題來了,如果我想擷取別人網站上提供的資料腫麼做到呢?也就是跨域讀取資料問題(不要鑽牛角說你不需要讀取其他網站的資料,相信我,你早晚得需要),json行不行呢?答案是No Way,為什麼呢,因為json只是普通的文字格式設定,能讓你這樣就輕鬆拿到那服務端就沒有任何安全和保密性可言了,這樣的話互連網世界非亂套不可,這個問題那些牛X的規範制定者早就想到了,所以使用了同源策略來限制檔案擷取。最後的結果就是只有像img、script、iframe這類可以指定src屬性的標籤有跨域擷取別人網站上資料(圖片,指令碼,源檔案其實都是資料)的能力。比如:
<!--京東商品圖片--><img src="yun_qi_img/56615e00N7a475ee6.jpg" /><!--百度CDN--><script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
看來直接擷取json是行不通了,那有沒有其他方法能拿到資料呢?於是乎jsonp就這樣被聰明的開發人員給發現了,為什麼說是發現而不是發明呢,因為並沒有涉及到任何新技術,就像發現ajax一樣。
jsonp原理是這樣的,網站A需要擷取網站B的資料,網站B說我給你們一個方法,【1. 你們使用<script src="http://www.B.com/open.js"></script>標籤先擷取到open.js檔案(網站B的責任),這裡邊有你們需要的資料。2. 你們擷取資料後處理資料(總得處理資料吧)的方法名必須命名為foo(資料要求者的責任和義務)】,這裡相當於B網站和請求擷取資料者之間建立了一個協議,要求要求者務必按照規則辦事,如果要求者不能同時遵守上面兩條就不能按預期擷取資料。額..,這也算相當於建立了一個潛規則吧
open.js內容
foo({"name":"B","age":23}); //為什麼不直接寫成json資料{"name":"B","age":23}呢,原因很簡單,在js檔案總得合乎js文法吧//這也是為什麼協議中明確規定處理資料的方法名必須命名為foo,因為B網站是在假定要求者的指令碼中已經定義了資料處理方法foo的情況下返回資料;//不然就會報foo is not defined錯誤
網站A指令碼須有
function foo(data){console.log(data);//ToDo.. }
啊!雖然拐了個彎,但資料總算得到了,網站A,網站B都非常高興,那麼問題又來了,網站C說也需要擷取網站B的資料,網站B把協議甩給它,網站C拿過來一看,草泥馬啊,foo這個名字已經在自己的指令檔的6868行用過了,而且已經使用在指令碼的各個角落,批量替換會導致很多潛在bug啊,網站B情急之下決定把foo改成fool,網站A立馬蹦起來,因為自己的網站已經在很多地方使用foo引用了資料。
為了避免上面情況發生,那些牛X哄哄的開發人員使用了動態產生js檔案的方法,php版本如下:
open.php
<?phpheader('Content-type: application/javascript');$jsonCallback = htmlspecialchars($_REQUEST ['callback']); //擷取要求者自訂的回呼函數名$jsonData ='{"name":"B","age":23}'; //待返回的json資料echo $jsonCallback . "(" . $jsonData . ")"; //輸出jsonp格式的資料,即一行函數調用語句?>
額 ..,至於php為什麼能返回js格式檔案,自行百度。
於是網站A用<script src="http://www.B.com/open.php?callback=foo"></script>來請求資料,不需要修改任何變數,返回給A的指令檔內容是:
foo({"name":"B","age":23}); //所謂的jsonp,就是一句函數調用,資料都被包裹傳遞到參數中了,千萬別穿個馬甲就不認識了 網站C就用<script src="http://www.B.com/open.php?callback=blah"></script>來請求資料,返回給C的指令檔內容是:blah({"name":"B","age":23}); 網站N就用<script src="http://www.B.com/open.php?callback=what"></script>來請求資料,返回給N的指令檔內容是:what({"name":"B","age":23});
Problem Solved,大家都取到了期望的資料,並且避免了命名衝突。
jsonp全名叫做json with padding,很形象,就是把json對象用符合js文法的形式包裹起來以使其它網站可以請求得到,也就是將json資料封裝成js檔案;
json是理想的資料交換格式,但沒辦法跨域直接擷取,於是就將json包裹(padding)在一個合法的js語句中作為js檔案傳過去。這就是json和jsonp的區別,json是想要的東西,jsonp是達到這個目的而普遍採用的一種方法,當然最終獲得和處理的還是json。所以說json是目的,jsonp只是手段。json總會用到,而jsonp只有在跨域擷取資料才會用到。
理解了json和jsonp的區別之後,其實ajax裡的跨域擷取資料就很好理解和實現了,同源時候並沒有什麼特別的,直接取就行,跨域時候需要拐個彎來達到目的。
附上jquery中ajax請求json資料執行個體:
(同源):
$.ajax({url:"persons.json",success:function(data){ console.log(data); //ToDo.. }});
(跨域):
$.ajax({url:"http://www.B.com/open.php?callback=?",dataType:"jsonp",success:function(data){console.log(data);//ToDo..}});
jquery已把jsonp封裝進ajax,很合理,因為畢竟絕大多數的jsonp請求都是ajax,關於jquery的ajax具體用法請自行百度,另外要注意的一點就是不同的網站提供的資料介面的$_REQUEST ['callback']中不一定絕對是callback也可能是cb,cbk等,具體使用時務必閱讀服務端提供的有關介面使用的詳細文檔。
下面給大家介紹下由“夜未央0906”寫的通過ajax獲得json資料後格式的轉換
在有些情況下擷取到的json資料可能是string類型的,需要把其格式化為json對象才方便解析。
a)原生js通過ajax擷取到的json
此時返回的資料預設是string型的,所以需要用eval()函數將其轉化為json對象。需要注意函數內字串的格式:eval(“(” + data+“)”),因為返回的string是在{}裡面的,eval會將大括弧識別為js代碼塊開始和結束的標誌,所以必須加上(),將其強制轉化為對象來處理。
b)jquery擷取
1:通過ajax()非同步請求並把type設定為json,返回的就是json對象。
2:通過用與ajax()等價的$.getJSON(url,data1,function(data2,status,xhr){//......})方法擷取的也是json對象。其中data1為連同請求發送的資料,data2為伺服器返回的資料即json對象。