
文章介紹
這是一篇,引導(dǎo)文吧... 因?yàn)閷戇@篇文章時(shí),實(shí)在想不出該如何分序。因此以實(shí)現(xiàn)跨域訪問(wèn)為目的,從基礎(chǔ)知識(shí)往上寫。最后以百度搜索智能提示為例,來(lái)講解跨域的具體應(yīng)用!
內(nèi)容
首先,我們得明確什么是跨域,這里先了解一下url中各組成部分
以百度為例:
https://www.baidu.com:80
協(xié)議:https://
二級(jí)域名:www
一級(jí)域名:baidu.com
端口號(hào):80
以上4個(gè)有一個(gè)不同即為跨域訪問(wèn),比如你當(dāng)前頁(yè)面在https://www.baidu.com:80,你去用Ajax請(qǐng)求https://tieba.baidu.com:80的數(shù)據(jù),就相當(dāng)于跨域訪問(wèn)!
在Ajax中,是不支持跨域訪問(wèn)的,所以www.baidu.com拿不到tieba.baidu.com上的數(shù)據(jù)。
那么這里就要用到跨域訪問(wèn)的技巧,雖然Ajax不支持,但我們可以利用src這個(gè)屬性達(dá)到目的。
對(duì)于src這個(gè)屬性,相信很多人都會(huì)想到img標(biāo)簽!我們都知道img標(biāo)簽的src如果設(shè)置為一個(gè)網(wǎng)絡(luò)地址時(shí),那么就會(huì)去使用該網(wǎng)絡(luò)地址的圖片資源。
比如src=https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png
那么img標(biāo)簽就會(huì)請(qǐng)求該url的數(shù)據(jù)返回來(lái),其實(shí)這就已經(jīng)是跨域訪問(wèn)了。因?yàn)槟惝?dāng)前的頁(yè)面并不在https://ss0.bdstatic.com上,但你卻成功訪問(wèn)到了它的資源。
因此我們可以利用src這個(gè)利器,達(dá)到我們跨域訪問(wèn)的目的。
不過(guò)使用src之前,得先了解一下Ajax利用請(qǐng)求回來(lái)的響應(yīng)數(shù)據(jù)執(zhí)行回調(diào)的一種方法:
//先定義一個(gè)函數(shù),等會(huì)利用該函數(shù)執(zhí)行回調(diào)
function fun (obj) {
console.log(obj);
}
//以下均為ajax請(qǐng)求,粗略看即可
var url = 'test.php';//訪問(wèn)當(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) {
//請(qǐng)求成功后,拿到返回字符串并使用eval執(zhí)行
eval(xhr.responseText);
} else {
console.log('請(qǐng)求失敗');
}
}
}
為了拿到請(qǐng)求數(shù)據(jù),下面我們利用php簡(jiǎn)單制作一個(gè)后端接口test.php
<?php
//創(chuàng)建一個(gè)php對(duì)象 name:kevin,age:23
$obj = array("name"=>"Kevin","age"=>"23");
//將php對(duì)象編碼為json格式的字符串
$json = json_encode($obj);
//后端給客戶端返回一個(gè)字符串 點(diǎn)為字符串拼接(相當(dāng)于js中加號(hào))
echo("fun(" . $json . ")");
請(qǐng)求成功后eval(xhr.responseText);這一句可以一步步分解為如下代碼:
- eval(xhr.responseText);
- eval(fun({"name":"Kevin", "age":"23"}));
- fun({"name":"Kevin", "age":"23"});
- console.log({"name":"Kevin", "age":"23"})
因此控制臺(tái)打印如下:

以上我們實(shí)現(xiàn)了:根據(jù)后端返回的數(shù)據(jù)來(lái)決定具體執(zhí)行某一個(gè)函數(shù),并且利用請(qǐng)求回來(lái)的數(shù)據(jù)傳參!
但是以上并沒(méi)有解決我們跨域需求,因?yàn)槲艺?qǐng)求的后端接口,依然在當(dāng)前域!
那么我剛才說(shuō)了,利用src,我們就能實(shí)現(xiàn)跨域。假如我們使用img標(biāo)簽,使其src="test.php"。這樣我們雖然拿到了數(shù)據(jù),但是img標(biāo)簽并不會(huì)像eval函數(shù)一樣幫我們執(zhí)行數(shù)據(jù),這樣數(shù)據(jù)就得不到利用。
所以對(duì)于實(shí)現(xiàn)跨域,我們有這樣的需求:
- 有src屬性
- 可以像eval函數(shù)一樣將數(shù)據(jù)執(zhí)行!
滿足以上條件的確實(shí)有,那就是script標(biāo)簽。
平時(shí)我們?cè)趕cript標(biāo)簽內(nèi)寫代碼,其實(shí)寫的就是字符串,并且script標(biāo)簽會(huì)幫我們執(zhí)行。
并且我們平時(shí)經(jīng)常會(huì)用到script標(biāo)簽的src屬性,比如引入框架時(shí),下面以jQuery為例:
<script src="./jquery.js"></script>
其實(shí)它就相當(dāng)于執(zhí)行了如下:
<script>
//一大堆jQ代碼字符串...
</script>
因此我們可以利用script標(biāo)簽就行跨域訪問(wèn),這里以百度為例:
這是百度搜索時(shí),搜索提示的數(shù)據(jù)接口
https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=關(guān)鍵字&cb=方法名
比如我搜索a,頁(yè)面如下:

那么我利用接口url也會(huì)得到上面數(shù)據(jù),如圖:

這里方法名會(huì)根據(jù)我們的參數(shù)返回,因此你請(qǐng)求數(shù)據(jù)成功后要執(zhí)行什么函數(shù),那么就往cb傳該函數(shù)的方法名!
下面我用盡量少的代碼實(shí)現(xiàn)一下 百度搜索提示
<body>
<!--搜索框-->
<input type="text" id="input">
<!--數(shù)據(jù)請(qǐng)求回來(lái)后,往里面添加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,那么就會(huì)執(zhí)行代碼
document.body.appendChild(script);
};
</script>
</body>
最后實(shí)現(xiàn)效果如下:

代碼僅以實(shí)現(xiàn)效果為目的,寫得很簡(jiǎn)短,大家可以直接拷貝到自己電腦嘗試~