DEMO : JSONP示例
為什么使用JSONP
JSONP和JSON是不一樣的。JSON(JavaScript Object Notation
)是一種基於文本的數據交換方式,或者叫做數據描述格式。而JSONP(JSON with Padding
)是一種方式或者說非強制性協議。它是為了解決某個難題而產生的一種技術方式。
為什么會用到JSONP呢?
我們平時在用ajax請求服務端數據時,一般是這么寫的:
$.ajax({
type: "get",
url: "getData.php",
dataType: "json",
success: function (data, textStatus, jqXHR) {
console.log(data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('fail');
}
});
這是一段很普通的基於jQuery的AJAX請求,不會有什么問題。注意到:url
里是getData.php
,說明這個文件url是基於當前服務器的,例如可能是localhost
,也就是前端發出的請求來源是localhost
,后端肯定也是localhost
。他們倆是在同一個域名下。當然,平時我們也不會特別注意。
這時候,假如這個url
變成其它服務器上的地址,例如:'http://apis.juhe.cn/mobile/get?phone=13429667914&key='
,我們再把請求發送出去,會發現出問題了。大家可以手動寫個示例看看。
DEMO: 為什么使用jsonp?
出什么問題了?被限制請求了!
XMLHttpRequest cannot load http://apis.juhe.cn/mobile/get?phone=13429667914&key=. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://demo.52fhy.com' is therefore not allowed access.
也就是請求來源與服務器不是同一個域名,不允許訪問。這就是瀏覽器同源策略:
所謂"同源"指的是"三個相同":
協議相同
域名相同
端口相同
舉例來說,http://www.example.com/dir/page.html這個網址,協議是http://,域名是www.example.com,端口是80(默認端口可以省略)。它的同源情況如下。
http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)
同源政策規定,AJAX請求只能發給同源的網址,否則就報錯。
那么,這時候該怎么辦呢?我就是想通過js請求對方服務器上的資源!
除了架設服務器代理(瀏覽器請求同源服務器,再由后者請求外部服務),有三種方法規避這個限制。
- JSONP
- WebSocket
- CORS
本文只對JSONP作介紹。
如何使用JSONP
首先前端這邊代碼得改改,假設先不用jQuery:
<script type="text/javascript">
//跨域發送HTTP請求,從服務端獲取數據,callback指定回調函數名稱
var url = 'http://demo.52fhy.com/jsonp/handJsonp.php?callback=handler';
function getHello() {
var script = document.createElement('script');
script.setAttribute('src', url);
document.querySelector("head").appendChild(script);
}
// 處理函數
function handler(data) {
console.log(data);
// our code here...
}
</script>
<input type="button" value="發送跨域HTTP請求,獲取數據" onclick="getHello()" />
后端服務器也要改改。
例如,在PHP語言中,后端服務器在API里返回JSON數據,一般是這么寫的:
$data = array('name' => '52fhy', 'age' => '22');
echo json_encode($data);
exit;
這里需要改成:
$data = array('name' => '52fhy', 'age' => '22');
handJsonp($data);
//處理jsonp
function handJsonp($data){
$callback = $_GET['callback'] ? : 'callback'; //默認使用callback
echo sprintf("%s(%s)", $callback, json_encode($data));
exit;
}
一旦請求成功,服務端輸出了:
handler({name: "52fhy", age: "22"});
這時候瀏覽器就要響應了,找到handler()
方法並執行,恰好,我們提前定義好了handler()
方法。
這里為什么服務端沒有限制訪問呢?原因是我們通過動態添加了個:
<script src="http://demo.52fhy.com/jsonp/handJsonp.php?callback=handler"></script>
它的基本思想是,網頁通過添加一個<script>
元素,向服務器請求JSON數據,這種做法不受同源政策限制;服務器收到請求后,將數據放在一個指定名字的回調函數里傳回來。
這種方法就是JSONP。
使用jQuery/Zepto
如果使用jQuery/Zepto,JSONP的方式將會和發送非跨域請求那樣簡單。
示例:
$.ajax({
type: "get",
async: false,
url: "http://demo.52fhy.com/jsonp/handJsonp.php",
dataType: "jsonp",
success: function (data, textStatus, jqXHR) {
console.log(data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('fail');
console.log(XMLHttpRequest, textStatus, errorThrown);
}
});
只需要將dataType設置成jsonp
就可以進行跨域請求了。在success里我們能接收到來自服務端的響應:
{name: "52fhy", age: "22"}
DEMO: Zepto jsonp demo
通過console控制台,可以看到請求信息:
Request URL:http://demo.52fhy.com/jsonp/handJsonp.php?_=1460899828609&callback=jsonp1
Request Method:GET
Status Code:200 OK
jQuery/Zepto為我們封裝好了回調函數,一般情況下不需要我們單獨去寫,如果你不想在success中處理,想單獨寫處理函數,那么可以通過設置這2個參數來實現:
jsonp: "callback",//傳遞給服務端的回調函數名稱參數,如果不設置此項,則默認是"callback"
jsonpCallback: "handler",//傳遞給服務端的回調函數名稱,如果不設置此項,jQuery默認是形如"jQuery18308539637457579374_1460898291266"的由jQuery自動生成的函數名稱,Zepto默認是`jsonp1`
如果是zepto,可以在success回調里面使用console.log(jsonp1)
,發現jsonp1()
方法是存在的。
需要注意的是:
1.JSONP雖然看起來很像一般的ajax請求,但其原理不同,JSONP是通過
<script>
標簽的動態加載來實現的跨域請求,而一般的ajax請求是通過XMLHttpRequest
對象進行;
2.JSONP不是一種標准協議,其安全性和穩定性都不如 W3C 推薦的 CORS;
3.JSONP不支持POST請求,即使把請求類型設置為post,其本質上仍然是一個get請求。
參考
1、瀏覽器同源政策及其規避方法 - 阮一峰的網絡日志
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
2、跨域資源共享 CORS 詳解 - 阮一峰的網絡日志
http://www.ruanyifeng.com/blog/2016/04/cors.html
3、說說JSON和JSONP,也許你會豁然開朗_知識庫_博客園
http://kb.cnblogs.com/page/139725/
4、跨域解決方案二:使用JSONP實現跨域 - choon - 博客園
http://www.cnblogs.com/choon/p/5393682.html
5、JSON-P: Safer cross-domain Ajax with JSON-P/JSONP
http://json-p.org/