1. 程式人生 > >JSONP跨域原理和jQuery.getJSON用法

JSONP跨域原理和jQuery.getJSON用法

JSONP是一個非官方的協議,它允許在伺服器端整合Script tags返回至客戶端,通過javascript callback的形式實現跨域訪問(這僅僅是JSONP簡單的實現形式)。JSON系統開發方法是一種典型的面向資料結構的分析和設計方法,以活動為中心,一連串的活動的順序組合成一個完整的工作程序。

之所以會有跨域這個問題的產生根本原因是瀏覽器的同源策略限制,理解同源策略的限制同源策略是指阻止程式碼獲得或者更改從另一個域名下獲得的檔案或者資訊。也就是說我們的請求地址必須和當前網站的地指相同。同源策略通過隔離來實現對資源的保護。這個策略的歷史非常悠久從Netscape Navigator 2.0時代就開始了。

解決這個限制的一個相對簡單的辦法就是在伺服器端傳送請求,伺服器充當一個到達第三方資源的代理中繼。雖然是用廣泛但是這個方法卻不夠靈活。

另一個辦法就是使用框架(frames),將第三方站點的資源包含進來,但是包含進來的資源同樣要受到同源策略的限制。

有一個很巧妙的辦法就是在頁面中使用動態程式碼元素,程式碼的源指向服務地址並在自己的程式碼中載入資料。當這些程式碼載入執行的時候,同源策略就不會起到限制。但是如果程式碼試圖下載檔案的時候執行還是會失敗,幸運的是,我們可以使用JSON(JavaScript Object Notation)來改進這個應用。

JSON和JSONP

與XML相比,JSON是一個輕量級的資料交換格式。JSON對於JavaScript開發人員充滿魅力的原因在於JSON本身就是Javascript中的物件。

例如一個ticker物件

var ticker = {symbol:'IBM',price:100}

而JSON串就是 {symbol:'IBM',price:100}

這樣我們就可以在函式的引數中傳遞JSON資料。我們很容易掌握在函式中使用動態的JSON引數資料,但是我們的目的並不是這個。

通過使我們的函式能夠載入動態的JSON資料,我們就能夠處理動態的資料,這項技術叫做 Dynamic Javascript Insertion。

我們看下面的例子:

index.html中

  1. <script type="text/javascript">  
  2. function showPrice(data){  
  3. alert("Symbol:" + data.symbol + ", Price:" + data.price);  
  4. }  
  5. var url = "ticker.js"//Outer JS URL
  6. var script = document.createElement('script');  
  7. script.setAttribute('src', url);  
  8. //load javascript
  9. document.getElementsByTagName('head')[0].appendChild(script);  
  10. </script>  
  11. ticker.js中  
  12. var data = {symbol:'IBM', price:100};  
  13. showPrice(data); 

上面的程式碼通過動態加入Javascript程式碼,來執行函式載入資料。

正如之前提到過的,同源策略對於動態插入的程式碼不適用。也就是你可以從不同的域中載入程式碼,來執行在他們程式碼中的JSON資料。

這就是JSONP(JSON with Padding)。注意,使用這種方法時,你必須在頁面中定義回撥函式,就像上例中的showPrice一樣。

我們通常所說的JSONP服務(遠端JSON服務),實際上就是一種擴充套件的支援在使用者定義函式中包含返回資料的能力。這種方法依賴於必須接受一個回撥函式的名字作為引數。

然後執行這個函式,處理JSON資料,並顯示在客戶頁面上。

JQuery的JSONP支援

從JQery 1.2以後,就開始支援JSONP的呼叫。在另外的一個域名中指定好回撥函式名稱,你就可以用下面的形式來就載入JSON資料。

url?callback=?

示例:

  1. jQuery.getJSON(url + "&callbak=?"function(data)  
  2. {  
  3. alert("Symbol:" + data.symbol + ", Price:" + data.price);  
  4. }); 

jquery會在window物件中載入一個全域性的函式,當代碼插入時函式執行,執行完畢後就會被移除。同時jquery還對非跨域的請求進行了優化,如果這個請求是在同一個域名下那麼他就會像正常的Ajax請求一樣工作。

上例中我們在動態插入到頁面的程式碼中使用了靜態的json資料,雖然完成了依次JSONP返回,但仍不是JSONP服務,因為不支援在URL中定義回撥函式名稱。下面是一個將其變成JSONP服務的一個方法

伺服器端使用PHP。

首先我們來定義介面的規範,就像這樣:http://www.mydomain.com/jsonp/ticker?symbol=IBM&amp;callback=showPrice
symbol是請求條件,callback是回撥函式名稱。

在頁面檔案中,我們使用JQuery的支援:

  1. //JQuery JSONP Support
  2. var url = "http://www.mydomain.com/api/suggest.php?symbol=IBM&callback=?";  
  3. jQuery.getJSON(url, function(data){  
  4. alert("Symbol:" + data.symbol + ", Price:" + data.price);  
  5. }); 

在suggest.php中

  1. $jsondata = "{symbol:'IBM', price:120}";  
  2. echo $_GET['callback'].'('.$jsondata.')'

再舉個.NET webservice 的例子

客戶端

  1. $.getJSON(  
  2. "http://192.168.0.66/services/WebService1.asmx/ws?callback=?",  
  3. { name: "ff", time: "2pm" },  
  4. function(data) { alert(decodeURI(data.msg)) }  
  5. ); 

伺服器端

  1. [WebMethod]  
  2. publicvoid ws(string name,string time) {  
  3. HttpRequest Request = HttpContext.Current.Request;  
  4. string callback = Request["callback"];  
  5. HttpResponse Response = HttpContext.Current.Response;  
  6. Response.Write(callback + "({msg:'this is"+name+"jsonp'})");  
  7. Response.End();  

現在,如果我們想製作一些mashup,或者將第三方的資源整合到一個頁面中,我們就很容易想到JSONP的解決方法了。

注意:

JSONP是一個非常強大的構建mashp的方法,可是不是一個解決跨域訪問問題的萬能藥。它也有一些缺點:

第一也是最重要的:JSONP不提供錯誤處理。如果動態插入的程式碼正常執行,你可以得到返回,但是如果失敗了,那麼什麼都不會發生。你無法獲得一個404的錯誤,也不能取消這個請求。

另外一個重要的缺點是如果使用了不信任的服務會造成很大的安全隱患。