前言
因?yàn)闉g覽器同源策略的限制,無(wú)法向非同源地址發(fā)送 AJAX 請(qǐng)求(可以發(fā)送,但瀏覽器會(huì)拒絕接受響應(yīng))。
“同源”指的是“三個(gè)相同”:協(xié)議相同、域名相同、端口相同。
需求分析
我們需要在目標(biāo)網(wǎng)站(需要統(tǒng)計(jì)的網(wǎng)站)引入我們的JS腳本,在這個(gè)腳本中我們會(huì)對(duì)需要的數(shù)據(jù)做一下收集。然后把數(shù)據(jù)發(fā)送給統(tǒng)計(jì)系統(tǒng)。
但是作為統(tǒng)計(jì)系統(tǒng)(如百度、CNZZ等)和要統(tǒng)計(jì)的網(wǎng)站肯定是不同源的,所以就會(huì)有同源限制,無(wú)法發(fā)送AJAX請(qǐng)求。那應(yīng)該如何把統(tǒng)計(jì)到的數(shù)據(jù)跨域發(fā)送給統(tǒng)計(jì)系統(tǒng)呢?那就可以使用JSONP技術(shù)了。
jsonp是一種跨域解決方案,而不是一種技術(shù)。
因?yàn)閕mg、link、script是不受“同源策略”限制的,所以我們可以利用這些標(biāo)簽去發(fā)送一個(gè)get請(qǐng)求。> JSONP只支持GET請(qǐng)求,不支持POST請(qǐng)求。
具體代碼
前端代碼如下:
創(chuàng)建一個(gè)script標(biāo)簽,把獲取的數(shù)據(jù)拼接到src中,以get方式發(fā)送給后臺(tái)接口。然后把script標(biāo)簽插入頁(yè)面。
var isbaidu = 0; // 百度鏈接的類(lèi)型,定義為:1為百度廣告位鏈接,2為百度優(yōu)化鏈接
var wd = ""; // 用戶在百度搜索的關(guān)鍵詞
var parentURL=""; // 進(jìn)入本網(wǎng)站前的URL地址(在這里指的是從百度跳轉(zhuǎn)到同網(wǎng)站的地址,這個(gè)鏈接中可以獲取到我們需要的信息)
// 百度廣告位鏈接
if (parentURL.indexOf("baidu.com/baidu.php") != -1) {
isbaidu=1;
}else if (parentURL.indexOf("baidu.com/link") != -1){
isbaidu=2;
}
// 獲取百度的地址URL
try{if(opener.document.referrer.length>0){parentURL=opener.document.referrer;}}catch(e){parentURL=document.referrer;}
parentURL = parentURL.toLowerCase();
// 獲取用戶搜索關(guān)鍵詞
arr = parentURL.split("?");
arrurl = arr[1].split("&");
for (i = 0; i <= arrurl.length - 1; i++) {
arr2 = arrurl[i].split("=");
for (j = 0; j <= arr2.length - 1; j++) {
if (arr2[0] == "wd" || arr2[0] == "word") {
wd = arr2[1];
}
}
}
//直接進(jìn)來(lái)才是空的,如果不為空則是刷新操作。過(guò)濾過(guò)刷新導(dǎo)致的無(wú)用數(shù)據(jù)
if (window.name == "") {
if(isbaidu){
/**JSONP核心代碼**/
// 把要發(fā)送的數(shù)據(jù)拼接到scr地址上,以get方式發(fā)送給后臺(tái)
// 【如果需要獲取后臺(tái)返回的數(shù)據(jù),則需要定義一個(gè)回調(diào)數(shù)據(jù)來(lái)處理數(shù)據(jù)】
// callback定義了一個(gè)回調(diào)函數(shù)名,后臺(tái)輸出一個(gè)函數(shù)調(diào)用,格式如:回調(diào)函數(shù)(返回?cái)?shù)據(jù)),直接把數(shù)據(jù)作為回調(diào)函數(shù)的實(shí)參傳遞回來(lái)。
// 前端直接定義這個(gè)回調(diào),然后形參就是后臺(tái)傳遞回來(lái)的數(shù)據(jù)
var JSONP=document.createElement("script");
JSONP.type="text/javascript";
JSONP.src="http://www.jk1201.com/getinfo.php?callback=jsonpCallback&itemid="+_item_id+"&isbaidu="+isbaidu+"&wd="+wd;
document.getElementsByTagName("head")[0].appendChild(JSONP);
}
}
window.name = "frombaidu"; // 刷新當(dāng)前頁(yè)面,window.name并不會(huì)銷(xiāo)毀
// 如果只是為了統(tǒng)計(jì)信息才不需要這個(gè)回調(diào)函數(shù),只有需要獲取后臺(tái)返回的數(shù)據(jù)時(shí)才會(huì)使用這個(gè)回調(diào)數(shù)據(jù)獲取數(shù)據(jù)。
function jsonpCallback(result){
// 前端就可以根據(jù)后臺(tái)返回的數(shù)據(jù)(result)來(lái)作相應(yīng)的操作了。
console.log(result)
}
后臺(tái)代碼(這里是php代碼)如下:
<?php
// ...
// 一頓操作猛如虎,處理數(shù)據(jù)并獲取需要回傳到前端的數(shù)據(jù)$result = 'abc'
//動(dòng)態(tài)執(zhí)行回調(diào)函數(shù)
$callback=$_GET['callback'];
echo $callback."($result)";
?>
最終get請(qǐng)求會(huì)在頁(yè)面返回輸出 jsonpCallback('abc'),也就是執(zhí)行了前端定義好的回調(diào)函數(shù),從而拿到了后臺(tái)返回的結(jié)果。然后就能用這個(gè)返回結(jié)果('abc')做對(duì)應(yīng)處理了。