天天看點

AJAX 跨域請求 - JSONP擷取JSON資料 jsson和jsonp

Asynchronous JavaScript and XML (Ajax ) 是驅動新一代 Web 站點(流行術語為 Web 2.0 站點)的關鍵技術。Ajax 允許在不幹擾 Web 應用程式的顯示和行為的情況下在背景進行資料檢索。使用 

XMLHttpRequest

 函數擷取資料,它是一種

API,允許用戶端 JavaScript 通過 HTTP 連接配接到遠端伺服器。Ajax 也是許多 mashup 的驅動力,它可将來自多個地方的内容內建為單一 Web 應用程式。

不過,由于受到浏覽器的限制,該方法不允許跨域通信。如果嘗試從不同的域請求資料,會出現安全錯誤。如果能控制數 據駐留的遠端伺服器并且每個請求都前往同一域,就可以避免這些安全錯誤。但是,如果僅停留在自己的伺服器上,Web 應用程式還有什麼用處呢?如果需要從多個第三方伺服器收集資料時,又該怎麼辦?

了解同源政策限制

同源政策阻止從一個域上加載的腳本擷取或操作另一個域上的文檔屬性。也就是說,受到請求的 URL 的域必須與目前 Web 頁面的域相同。這意味着浏覽器隔離來自不同源的内容,以防止它們之間的操作。這個浏覽器政策很舊,從 Netscape Navigator 2.0 版本開始就存在。

克服該限制的一個相對簡單的方法是讓 Web 頁面向它源自的 Web 伺服器請求資料,并且讓 Web 伺服器像代理一樣将請求轉發給真正的第三方伺服器。盡管該技術獲得了普遍使用,但它是不可伸縮的。另一種方式是使用架構要素在目前 Web 頁面中建立新區域,并且使用 

GET

 請求擷取任何第三方資源。不過,擷取資源後,架構中的内容會受到同源政策的限制。

克服該限制更理想方法是在 Web 頁面中插入動态腳本元素,該頁面源指向其他域中的服務 URL 并且在自身腳本中擷取資料。腳本加載時它開始執行。該方法是可行的,因為同源政策不阻止動态腳本插入,并且将腳本看作是從提供 Web 頁面的域上加載的。但如果該腳本嘗試從另一個域上加載文檔,就不會成功。幸運的是,通過添加 JavaScript Object Notation (JSON) 可以改進該技術。

1、什麼是JSONP?

要了解JSONP,不得不提一下JSON,那麼什麼是

JSON

 ?

JSON is a subset of the object literal notation of JavaScript. Since JSON is a subset of JavaScript, it can be used in the language with no muss or fuss.

JSONP(JSON with Padding)是一個非官方的協定,它允許在伺服器端內建Script tags傳回至用戶端,通過javascript callback的形式實作跨域通路(這僅僅是JSONP簡單的實作形式)。

2、JSONP有什麼用?

由于同源政策的限制,XmlHttpRequest隻允許請求目前源(域名、協定、端口)的資源,為了實作跨域請求,可以通過script标簽實作跨域請求,然後在服務端輸出JSON資料并執行回調函數,進而解決了跨域的資料請求。

3、如何使用JSONP?

下邊這一DEMO實際上是JSONP的簡單表現形式,在用戶端聲明回調函數之後,用戶端通過script标簽向伺服器跨域請求資料,然後服務端傳回相應的資料并動态執行回調函數。

HTML代碼 (任一 ):

Html代碼  

AJAX 跨域請求 - JSONP擷取JSON資料 jsson和jsonp
  1. <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />  
  2. <script type="text/javascript">  
  3.     function jsonpCallback(result) {  
  4.         //alert(result);  
  5.         for(var i in result) {  
  6.             alert(i+":"+result[i]);//循環輸出a:1,b:2,etc.  
  7.         }  
  8.     }  
  9.     var JSONP=document.createElement("script");  
  10.     JSONP.type="text/javascript";  
  11.     JSONP.src="http://crossdomain.com/services.php?callback=jsonpCallback";  
  12.     document.getElementsByTagName("head")[0].appendChild(JSONP);  
  13. </script>  

或者

AJAX 跨域請求 - JSONP擷取JSON資料 jsson和jsonp
  1.         alert(result.a);  
  2.         alert(result.b);  
  3.         alert(result.c);  
  4. <script type="text/javascript" src="http://crossdomain.com/services.php?callback=jsonpCallback"></script>  

JavaScript的連結,必須在function的下面。

服務端PHP代碼 (services.php):

Php代碼  

AJAX 跨域請求 - JSONP擷取JSON資料 jsson和jsonp
  1. <?php  
  2. //服務端傳回JSON資料  
  3. $arr=array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);  
  4. $result=json_encode($arr);  
  5. //echo $_GET['callback'].'("Hello,World!")';  
  6. //echo $_GET['callback']."($result)";  
  7. //動态執行回調函數  
  8. $callback=$_GET['callback'];  
  9. echo $callback."($result)";  

如果将上述JS用戶端代碼用jQuery的方法來實作,也非常簡單。

$.getJSON

$.ajax

$.get

用戶端JS代碼在jQuery中的實作方式1:

Js代碼  

AJAX 跨域請求 - JSONP擷取JSON資料 jsson和jsonp
  1. <script type="text/javascript" src="jquery.js"></script>  
  2.     $.getJSON("http://crossdomain.com/services.php?callback=?",  
  3.     function(result) {  
  4.     });  

用戶端JS代碼在jQuery中的實作方式2:

AJAX 跨域請求 - JSONP擷取JSON資料 jsson和jsonp
  1.     $.ajax({  
  2.         url:"http://crossdomain.com/services.php",  
  3.         dataType:'jsonp',  
  4.         data:'',  
  5.         jsonp:'callback',  
  6.         success:function(result) {  
  7.             for(var i in result) {  
  8.                 alert(i+":"+result[i]);//循環輸出a:1,b:2,etc.  
  9.             }  
  10.         },  
  11.         timeout:3000  

用戶端JS代碼在jQuery中的實作方式3:

AJAX 跨域請求 - JSONP擷取JSON資料 jsson和jsonp
  1.     $.get('http://crossdomain.com/services.php?callback=?', {name: encodeURIComponent('tester')}, function (json) { for(var i in json) alert(i+":"+json[i]); }, 'jsonp');  

其中 jsonCallback 是用戶端注冊的,擷取 跨域伺服器 上的json資料 後,回調的函數。

http://crossdomain.com/services.php?callback=jsonpCallback

這個 url 是跨域服務 器取 json 資料的接口,參數為回調函數的名字,傳回的格式為

AJAX 跨域請求 - JSONP擷取JSON資料 jsson和jsonp
  1. jsonpCallback({msg:'this is json data'})  

Jsonp原理: 

首先在用戶端注冊一個callback, 然後把callback的名字傳給伺服器。

此時,伺服器先生成 json 資料。

然後以 javascript 文法的方式,生成一個function , function 名字就是傳遞上來的參數 jsonp.

最後将 json 資料直接以入參的方式,放置到 function 中,這樣就生成了一段 js 文法的文檔,傳回給用戶端。

用戶端浏覽器,解析script标簽,并執行傳回的 javascript 文檔,此時資料作為參數,傳入到了用戶端預先定義好的 callback 函數裡.(動态執行回調函數)

使用JSON的優點在于:

  • 比XML輕了很多,沒有那麼多備援的東西。
  • JSON也是具有很好的可讀性的,但是通常傳回的都是壓縮過後的。不像XML這樣的浏覽器可以直接顯示,浏覽器對于JSON的格式化的顯示就需要借助一些插件了。
  • 在JavaScript中處理JSON很簡單。
  • 其他語言例如PHP對于JSON的支援也不錯。

JSON也有一些劣勢:

  • JSON在服務端語言的支援不像XML那麼廣泛,不過JSON.org上提供很多語言的庫。
  • 如果你使用eval()來解析的話,會容易出現安全問題。

盡管如此,JSON的優點還是很明顯的。他是Ajax資料互動的很理想的資料格式。

主要提示:

JSONP 是建構 mashup 的強大技術,但不幸的是,它并不是所有跨域通信需求的萬靈藥。它有一些缺陷,在送出開發資源之前必須認真考慮它們。

第一,也是最重要的一點,沒有關于 JSONP 調用的錯誤處理。如果動态腳本插入有效,就執行調用;如果無效,就靜默失敗。失敗是沒有任何提示的。例如,不能從伺服器捕捉到 404 錯誤,也不能取消或重新開始請求。不過,等待一段時間還沒有響應的話,就不用理它了。(未來的 jQuery 版本可能有終止 JSONP 請求的特性)。

JSONP 的另一個主要缺陷是被不信任的服務使用時會很危險。因為 JSONP 服務傳回打包在函數調用中的 JSON 響應,而函數調用是由浏覽器執行的,這使宿主 Web 應用程式更容易受到各類攻擊。如果打算使用 JSONP 服務,了解它能造成的威脅非常重要。