參考個人博客:http://www.zhuzhuman.com/nav-1/type-1/article/20.html
我們平常使用ajax從前端發起請求獲取數據,一般請求的地址都是和當前網頁是同源的,即不能進行跨域請求,(跨域:主域名、子域名、端口號其中有一個不同就屬於跨域);
Jsonp(JSON with Padding) 是 json 的一種"使用模式",可以讓網頁從別的域名(網站)那獲取資料,即跨域讀取數據。
雖然普通ajax不能跨域,但是script標籤是可以跨域引用的,即JS可以跨域使用。因此:
jsonp實現跨域請求數據的原理:jsonp允許服務器在後臺生成一段js代碼(回調函數),將數據寫進回調函數裏,然後返回給頁面,頁面接收回調函數後在頁面執行,可獲取到數據。注:因此,jsonp返回給頁面的不是數據本身,而是回調函數,數據可從回調函數中獲取。
舉例:
- jquery寫法:
第一種寫法:ajax
<script type="text/javascript">
// 前端通過jquery發起ajax請求
$.ajax({
type : "GET", // 獲取方式,好像jsonp不支持post...
url : "http://127.0.0.1/jsonp/jsonp.php", // 請求的地址
async:false, // 同步
dataType : "jsonp", // 數據類型,必須是jsonp,這樣才能進行跨域操作
data : "", // 傳給後臺的數據,可省略。
jsonp : "callback", // 用於指定回調函數,可爲任意名字,但是必須和後臺用GET獲取用的名字保持一致。
jsonpCallback : "myCallBack", // 自定義回調函數名,可省略,默認jq會自動隨機生成函數名傳給後臺。
success : function (data) { // 請求成功時執行的函數,其中data就是後臺數據。
console.log(data);
},
error : function (e) {
console.log("e");
}
})
</script>
第二種寫法: get請求
<script type="text/javascript">
$.getJSON('http://127.0.0.1/jsonp/jsonp.php?callback=?',function (data) {
console.log(data);
}); // ?後面的callback=?用來標識是jsonp請求。其中callback必須和後臺get獲取數據時用的名字一樣。
</script>
2.原生JS實現jsonp
function jsonp(options) {
// 請求參數設置
options = options || {};
// 創建js標籤用於執行jsonp
var oHead = document.getElementsByTagName('head')[0];
var oScript = document.createElement('script');
// 給window綁定和callback參數值相同的函數,用於獲數據
var _callback = options.callback;
window[_callback] = function (data) {
// 形參data 用於接收後臺返回的 callback函數 的實參(數據)
// 獲取數據成功後清除jsonp的js
oHead.removeChild(oScript);
// 清除加載超時的定時函數(加載成功,超時函數不用執行了)
clearTimeout(oScript.timer);
// 清除回調函數
window[_callback] = null;
// 執行請求成功的回調函數,把callback裏的參數再傳給succeed函數。succeed 函數裏面執行對數據的操作
options.success && options.success(data);
}
// js發起請求,請求成功後返回的代碼是讓 callback 執行的,而且實參就是後臺數據
var url = options.url.indexOf('?') > -1 ? options.url + '&callback=' + options.callback : options.url + '?callback=' + options.callback;
if(options.data) {
for(var k in options.data) {
url += '&' + k + '=' + options.data[k];
}
}
oScript.src = url;
oHead.appendChild(oScript);
// 超時函數,請求超時走error邏輯
if (options.timeout) {
oScript.timer = setTimeout(function() {
// 錯誤後清除回調函數
window[_callback] = null;
oHead.removeChild(oScript);
// 執行error函數
options.error && options.error({ message: "超時" });
}, options.timeout * 1000);
}
};
// 測試執行
var params = {
url: 'http://127.0.0.1/jsonp/jsonp.php',
callback: 'getback',
timeout: 10,
data: {
param1: 'a',
param2: 'b'
},
success: function(data) {
console.log(data);
},
error: function(e) {
console.log(e);
}
}; // 其他參數配置可根據需求添加
jsonp(params);
- 後臺文件jsonp.php寫法
<?php
// 要返回的數據
$data = '{
"shuju1" : "1",
"shuju2" : "2",
"shuju3" : "3",
"shuju4" : "4",
"shuju5" : "5"
}';
// 獲取請求傳過來的值,用於定義要返回的回調函數名,
$callback = $_GET['callback']; // 中括號裏的'callback',必須和前端ajax裏的的jsonp:"callback",中jsonp的值名字一樣
// 將回調函數名和數據拼接成函數的形式。數據以入參的形式傳入。
echo $callback . "(" . $data . ")";
?>