文章介紹
這是一篇客税,引導(dǎo)文吧... 因?yàn)閷戇@篇文章時况褪,實(shí)在想不出該如何分序。因此以實(shí)現(xiàn)跨域訪問為目的更耻,從基礎(chǔ)知識往上寫测垛。最后以百度搜索智能提示為例,來講解跨域的具體應(yīng)用秧均!
內(nèi)容
首先食侮,我們得明確什么是跨域,這里先了解一下url中各組成部分
以百度為例:
https://www.baidu.com:80
協(xié)議:https://
二級域名:www
一級域名:baidu.com
端口號:80
以上4個有一個不同即為跨域訪問目胡,比如你當(dāng)前頁面在https://www.baidu.com:80
锯七,你去用Ajax請求https://tieba.baidu.com:80
的數(shù)據(jù),就相當(dāng)于跨域訪問誉己!
在Ajax中眉尸,是不支持跨域訪問的,所以www.baidu.com
拿不到tieba.baidu.com
上的數(shù)據(jù)巨双。
那么這里就要用到跨域訪問的技巧噪猾,雖然Ajax不支持筑累,但我們可以利用src這個屬性達(dá)到目的袱蜡。
對于src這個屬性,相信很多人都會想到img標(biāo)簽慢宗!我們都知道img標(biāo)簽的src如果設(shè)置為一個網(wǎng)絡(luò)地址時戒劫,那么就會去使用該網(wǎng)絡(luò)地址的圖片資源。
比如src=https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png
那么img標(biāo)簽就會請求該url的數(shù)據(jù)返回來婆廊,其實(shí)這就已經(jīng)是跨域訪問了。因?yàn)槟惝?dāng)前的頁面并不在https://ss0.bdstatic.com
上巫橄,但你卻成功訪問到了它的資源淘邻。
因此我們可以利用src這個利器,達(dá)到我們跨域訪問的目的湘换。
不過使用src之前宾舅,得先了解一下Ajax利用請求回來的響應(yīng)數(shù)據(jù)執(zhí)行回調(diào)的一種方法:
//先定義一個函數(shù),等會利用該函數(shù)執(zhí)行回調(diào)
function fun (obj) {
console.log(obj);
}
//以下均為ajax請求彩倚,粗略看即可
var url = 'test.php';//訪問當(dāng)前目錄的php文件
var xhr = new XMLHttpRequest();
xhr.open('get',url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >=200 && xhr.status <300 || xhr.status == 304) {
//請求成功后,拿到返回字符串并使用eval執(zhí)行
eval(xhr.responseText);
} else {
console.log('請求失敗');
}
}
}
為了拿到請求數(shù)據(jù)筹我,下面我們利用php簡單制作一個后端接口test.php
<?php
//創(chuàng)建一個php對象 name:kevin,age:23
$obj = array("name"=>"Kevin","age"=>"23");
//將php對象編碼為json格式的字符串
$json = json_encode($obj);
//后端給客戶端返回一個字符串 點(diǎn)為字符串拼接(相當(dāng)于js中加號)
echo("fun(" . $json . ")");
請求成功后eval(xhr.responseText);
這一句可以一步步分解為如下代碼:
- eval(xhr.responseText);
- eval(fun({"name":"Kevin", "age":"23"}));
- fun({"name":"Kevin", "age":"23"});
- console.log({"name":"Kevin", "age":"23"})
因此控制臺打印如下:
以上我們實(shí)現(xiàn)了:根據(jù)后端返回的數(shù)據(jù)來決定具體執(zhí)行某一個函數(shù),并且利用請求回來的數(shù)據(jù)傳參帆离!
但是以上并沒有解決我們跨域需求蔬蕊,因?yàn)槲艺埱蟮?strong>后端接口,依然在當(dāng)前域哥谷!
那么我剛才說了岸夯,利用src麻献,我們就能實(shí)現(xiàn)跨域。假如我們使用img標(biāo)簽猜扮,使其src="test.php"勉吻。這樣我們雖然拿到了數(shù)據(jù),但是img標(biāo)簽并不會像eval函數(shù)一樣幫我們執(zhí)行數(shù)據(jù)旅赢,這樣數(shù)據(jù)就得不到利用齿桃。
所以對于實(shí)現(xiàn)跨域,我們有這樣的需求:
- 有src屬性
- 可以像eval函數(shù)一樣將數(shù)據(jù)執(zhí)行煮盼!
滿足以上條件的確實(shí)有短纵,那就是script標(biāo)簽。
平時我們在script標(biāo)簽內(nèi)寫代碼孕似,其實(shí)寫的就是字符串踩娘,并且script標(biāo)簽會幫我們執(zhí)行。
并且我們平時經(jīng)常會用到script標(biāo)簽的src屬性喉祭,比如引入框架時养渴,下面以jQuery為例:
<script src="./jquery.js"></script>
其實(shí)它就相當(dāng)于執(zhí)行了如下:
<script>
//一大堆jQ代碼字符串...
</script>
因此我們可以利用script標(biāo)簽就行跨域訪問,這里以百度為例:
這是百度搜索時泛烙,搜索提示的數(shù)據(jù)接口
https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=關(guān)鍵字&cb=方法名
比如我搜索a理卑,頁面如下:
那么我利用接口url也會得到上面數(shù)據(jù),如圖:
這里方法名會根據(jù)我們的參數(shù)返回蔽氨,因此你請求數(shù)據(jù)成功后要執(zhí)行什么函數(shù)藐唠,那么就往cb傳該函數(shù)的方法名!
下面我用盡量少的代碼實(shí)現(xiàn)一下 百度搜索提示
<body>
<!--搜索框-->
<input type="text" id="input">
<!--數(shù)據(jù)請求回來后鹉究,往里面添加li-->
<ul id="ul"></ul>
<script>
//回調(diào)方法,數(shù)據(jù)返回后觸發(fā)
function callBack(obj) {
//從上面圖知道關(guān)鍵字?jǐn)?shù)組位于數(shù)據(jù)的s屬性中
var array = obj.s;
//每次觸發(fā)先清空以前數(shù)據(jù),再添加
ul.innerHTML = "";
for (var i = 0; i < array.length; i++) {
var li = document.createElement('li');
li.innerText = array[i];
ul.appendChild(li);
}
}
//url1 和 url2 為了以后方便拼接
var url1 = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=';
var url2 = '&cb=';
var ul = document.getElementById('ul');
var input = document.getElementById('input');
//監(jiān)聽輸出框的鍵盤輸入
input.onkeyup = function () {
//創(chuàng)建script標(biāo)簽
var script = document.createElement('script');
//把輸入框的值和方法名作為url參數(shù)
script.src = url1 + this.value+ url2 + callBack.name;
//把script標(biāo)簽添加到body,那么就會執(zhí)行代碼
document.body.appendChild(script);
};
</script>
</body>
最后實(shí)現(xiàn)效果如下:
代碼僅以實(shí)現(xiàn)效果為目的宇立,寫得很簡短,大家可以直接拷貝到自己電腦嘗試~