JSONP用法詳解

admin發表於2018-08-01

在介紹JSONP之前,先來介紹下面一個事實:

使用ajax來請求資料這個大家都不會陌生,如果暫時不瞭解可以參閱ajax教程板塊。

但是並不允許ajax進行跨域請求,也就是說在請求不同域伺服器的資源時候,會出現報錯現象。

這種現象是由瀏覽器的同源策略導致的,跨域請求會因為安全問題而被拒絕。

JSONP英文全程是JSON with Padding,正是為解決這種跨域請求問題而誕生,並不是一種正式傳輸協議。

名稱看起來和JSON關係密切,其實並非如此,只是返回請求資料通常是JSON結構,當然也可以是其他資料。

下面就分佈介紹一下JSONP的實現原理。

一.普通的ajax請求:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!DOCTYPE html>  
<html>  
<head>  
<meta charset=" utf-8">  
<meta name="author" content="http://www.softwhy.com/" />  
<title>螞蟻部落</title>  
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>
<script>
$.ajax({
  type:'get',
  url:'http://www.softwhy.com/demo/JSON/php/antzone.php'
});
</script>
</head> 
<body> 
<div id="thediv"></div>
</body> 
</html>

特別說明:千萬不要在本站執行此程式碼,因為這相當於同域請求,所以不會出現任何問題。

如果在其他域執行此程式碼的時候就會出現跨域問題,截圖如下:

跨域被阻止圖片

二.html的自帶標籤可以實現跨域:

但是html的很多標籤自己就具有跨域功能,比如<script>標籤。

通常我們為了節省流量和提高速度,使用其他著名的CDN資源,比如上面程式碼中使用的jquery資源:

[HTML] 純文字檢視 複製程式碼
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>

很明顯上面的程式碼能夠實現跨域請求,其實凡是帶有src屬性的html標籤都具有跨域請求的能力,這個特點就是實現JSONP的契機。

三.實現程式碼:

我們希望獲取跨域伺服器上獲取xml檔案上的如下資料,並且顯示在指定的div中,xml檔案內容如下:

[XML] 純文字檢視 複製程式碼
<?xml version="1.0" encoding="utf-8" ?>
<bookstore>
  <book>
    <range>前端專區</range>
    <author>螞蟻部落</author>
    <target>css教程</target>
  </book>
  <book>
    <range>前端專區</range>
    <author>螞蟻部落</author>
    <target>div教程</target>
  </book>
  <book>
    <range>資源專區</range>
    <author>softwhy.com</author>
    <target>特效下載</target>
  </book>
  <book>
    <range>前端專區</range>
    <author>softwhy.com</author>
    <target>教程下載</target>
  </book>
</bookstore>

很明顯不能使用ajax跨域請求此xml檔案,然後進行處理。

那麼JSONP就要出場了,首先通過後臺語言將上面的XML檔案內容轉換為JSON格式,看如下程式碼:

[PHP] 純文字檢視 複製程式碼
<?php
  $path=$_SERVER["DOCUMENT_ROOT"].'/demo/JSON/XML/XML.xml';
  $json=json_encode(simplexml_load_file($path));
?>

轉換結果如下:

轉換結果

上面的unicode字元是將中文進行了轉碼,可以防止出現亂碼的情況。

然後在客戶端我們需要動態的建立一個<script>標籤,然後再進行請求以便實現跨域效果:

[JavaScript] 純文字檢視 複製程式碼
function getBooks(){
  var script=document.createElement('script');
  script.setAttribute('type','text/javascript');
  script.setAttribute('src','http://www.softwhy.com/demo/JSON/PHP/antzone.php?callback=Books');
  document.body.appendChild(script);
}

上面的程式碼動態建立了一個script標籤,然後設定標籤的src屬性值,這個屬性值最關鍵的地方是傳送一個函式的名稱,這個名稱會在php後臺經過處理包裝後,作為一個函式呼叫的形式返回,函式的引數就是轉換後的json格式資料,後臺轉換程式碼:

[PHP] 純文字檢視 複製程式碼
<?php
  $path=$_SERVER["DOCUMENT_ROOT"].'/demo/JSON/XML/XML.xml';
  $json=json_encode(simplexml_load_file($path));
  $callbackFn=$_GET['callback'];
  echo "$callbackFn($json);";
?>

完整前臺程式碼例項:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<script>
function books(books){
  var books=books.book;
  var booksContainer=document.getElementById('books');
  var str="";
  for(var index=0;index<books.length;index++){
    str=str+"<div>"+
      books[index]["range"]+","+
      books[index]["author"]+","+
       books[index]["target"]+
     "</div>";
  }
  booksContainer.innerHTML=str
}
function getBooks(){
  var script=document.createElement('script');
  script.setAttribute('type','text/javascript');
  script.setAttribute('src','http://www.softwhy.com/demo/JSON/php/antzone.php?callback=books');
  document.body.appendChild(script);
}
window.onload=function(){
  getBooks();
}
</script>
</head>
<body>
<div id="books"></div>
</body>
</html>

上面的程式碼實現了跨域請求效果,當然如果在本站執行不是跨域,在不同域下請求沒有任何問題。

下面做一下簡單總結:

(1).JSONP並不是一個官方的標準協議,而是程式設計師自己達成的一種約定俗成。

(2).實現跨域就是利用<script>標籤自帶的跨域能力。

(3).在請求頁面建立一個用來處理資料的函式。

(4).處理資料的函式名稱會被髮送到伺服器,經過包裝以後,要被處理的資料被當作函式的引數返回。

(5).後臺包裝返回的字串通過src加入scrpt標籤後就是一個js函式呼叫程式碼,於是跨域請求成功。