一、前言
- 初識(shí)
XMLHttpRequest cannot load xxxx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'xxxx' is therefore not allowed access. The response had HTTP status code 404.
timg.jpg
-
什么跨域?
簡(jiǎn)述:由于瀏覽器XMLHttpRequest同源策略(域名、端口、協(xié)議必須全一致)影響,禁止使用XHR對(duì)象向不同源服務(wù)器發(fā)起HTTP請(qǐng)求。 -
為啥禁止跨域?
簡(jiǎn)述:AJAX(XMLHttpRequest)同源策略主要用來(lái)防止CSRF攻擊。我們發(fā)起的每一次HTTP請(qǐng)求都會(huì)帶上請(qǐng)求地址對(duì)應(yīng)的cookie,簡(jiǎn)單來(lái)說(shuō)就是“模仿用戶”訪問“目標(biāo)網(wǎng)站”。 -
如何解決跨域?
簡(jiǎn)述:解決跨域問題的方案有很多,例如JSONP、CROS、反向代理等等。 - 今天我們就一起學(xué)習(xí)下,JSONP跨域解決方案的具體原理,以及實(shí)現(xiàn)封裝一個(gè)自己的jsonp.js。
二、JSONP
大家都知道頁(yè)面中,圖片(img)是可引用外部的,js腳本文件(script)也可引入外部的,所以基本原理就是通過(guò)動(dòng)態(tài)創(chuàng)建script標(biāo)簽,然后利用src屬性進(jìn)行跨域。
1. 基本原理
<body>
<script>
function fn1(str) { alert('我是fn1:'+ str) }
</script>
<script>
fn1('下面調(diào)用')
</script>
</body>
總結(jié):上面代碼想必大家都知道結(jié)果吧。會(huì)彈出“我是fn1:下面調(diào)用”
2. 百度搜索api簡(jiǎn)單使用
百度搜索的接口: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=abc&cb=show
<script>
function fn1(url){
window.show = function(json){
console.log(json);
}
var oS = document.createElement('script');
oS.src = url;
document.head.appendChild(oS);
}
fn1('https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=abc&cb=show');
</script>
結(jié)果如下圖所示
總結(jié):從上圖我們可以看出“abc”關(guān)鍵字的搜索結(jié)果可以展示了。也就是解決了跨域問題。
遺留問題:
- 創(chuàng)建的script標(biāo)簽,用完是不是需要?jiǎng)h除?
- 關(guān)鍵字(此處搜索內(nèi)容)是不是可以靈活進(jìn)行自定義?
- 等等
JSONP方法完善以及封裝
function json2url(json){
var arr = [];
for(var name in json){
arr.push(name+'='+json[name]);
}
return arr.join('&');
}
/*
** @jsonp jsonp跨域交互
** @params
** [object]
*/
function jsonp(json){
//參數(shù)初始值
json = json||{};
if(!json.url)return;
//回調(diào)名字
json.cbName = json.cbName||'cb';
//超時(shí)時(shí)間(ms)
json.timeout =json.timeout||15000;
//提交數(shù)據(jù)
json.data = json.data||{};
//回調(diào)函數(shù)的名字(解決了緩存問題)
json.data[json.cbName] = 'show'+Math.random();
//把回調(diào)函數(shù)名字中的.去掉。
json.data[json.cbName] = json.data[json.cbName].replace('.','');
//網(wǎng)絡(luò)超時(shí)
json.timer = setTimeout(function(){
window[json.data[json.cbName]] = function(){
oHead.removeChild(oS);
json.error&&json.error('親,網(wǎng)絡(luò)不給力');
};
},json.timeout);
//定義回調(diào)函數(shù)(全局的)
window[json.data[json.cbName]] = function(result){
//把網(wǎng)絡(luò)超時(shí)干掉
clearTimeout(json.timer);
//需要把script刪除
oHead.removeChild(oS);
//執(zhí)行成功回調(diào)函數(shù)
json.success&&json.success(result);
};
//獲取head標(biāo)簽。
var oHead = document.getElementsByTagName('head')[0];
//動(dòng)態(tài)創(chuàng)建script
var oS = document.createElement('script');
//給script加src
oS.src = json.url+'?'+json2url(json.data);
//把script插入到head標(biāo)簽中
oHead.appendChild(oS);
}