概念
當(dāng)一個(gè)資源從與該資源本身所在的服務(wù)器不同的域或端口請(qǐng)求一個(gè)資源時(shí)娩梨,資源會(huì)發(fā)起一個(gè)跨域 HTTP 請(qǐng)求。
出于安全考慮鲜锚,瀏覽器會(huì)限制從腳本內(nèi)發(fā)起的跨域HTTP請(qǐng)求。例如苫拍,XMLHttpRequest
和 Fetch遵循同源策略芜繁。因此,使用 XMLHttpRequest或 Fetch 的Web應(yīng)用程序只能將HTTP請(qǐng)求發(fā)送到其自己的域绒极。為了改進(jìn)Web應(yīng)用程序骏令,開(kāi)發(fā)人員要求瀏覽器廠商允許跨域請(qǐng)求。
解決方案
1. 如何使用CORS策略來(lái)進(jìn)行跨域操作
跨域資源共享(CORS)機(jī)制允許 Web 應(yīng)用服務(wù)器進(jìn)行跨域訪問(wèn)控制垄提,從而使跨域數(shù)據(jù)傳輸?shù)靡园踩M(jìn)行榔袋。瀏覽器支持在發(fā)送AJAX請(qǐng)求中使用CORS來(lái)降低HTTP請(qǐng)求所帶來(lái)的風(fēng)險(xiǎn)。
1.1 簡(jiǎn)單模式
- 在服務(wù)器后端方設(shè)置響應(yīng)頭response.setHeader ('Access-Control-Allow-Origin','http://xxxxx.com') 使用node.js監(jiān)聽(tīng)端口铡俐;('http://xxxxx.com' 為你要跨域的域名和端口)
response.setHeader('Access-Control-Allow-Origin','http://xxxxx.com:80')
- 或在使用http-server模擬時(shí)凰兑,加上以下命令
http-server -c-1 -p --cors="Access-Control-Allow-Origin: * "
即可使AJAX在請(qǐng)求時(shí),在響應(yīng)頭responseHeader里加入" Access-Control-Allow-Origin:* "字串,重新請(qǐng)求就可以得到Access-Control-Allow-Origin權(quán)限审丘,得到數(shù)據(jù)吏够。
1.2 復(fù)雜模式
在AJAX請(qǐng)求中,如果需要使用PUT/DELETE等高級(jí)方法時(shí)滩报,會(huì)返回報(bào)錯(cuò)字符串'Access-Control-Allow-Method'锅知,也需要在后端服務(wù)器中設(shè)置來(lái)開(kāi)放權(quán)限,加入以下語(yǔ)句:
response.setHeader('Access-Control-Allow-Method','GET,POST,OPTIONS')
即可得到'Access-Control-Allow-Method'內(nèi)由后端指定開(kāi)放的'GET,POST,OPTIONS'等權(quán)限脓钾。
2. 如何使用JSONP策略來(lái)進(jìn)行跨域操作
2.1 核心邏輯
在瀏覽器中售睹,只有XMLHttpRequest和Fetch會(huì)被同源原則限制,而script可训、css等直接請(qǐng)求的source和link并不會(huì)昌妹。利用這個(gè)特點(diǎn)生真,我們?nèi)绻麅H需要跨域來(lái)GET一個(gè)資源的話,可以直接使用<script>腳本來(lái)獲得數(shù)據(jù)捺宗。
2.2 JSONP是什么
JSONP = JSON + Padding 是跨域獲得的數(shù)據(jù)文件內(nèi)容的一種簡(jiǎn)寫(xiě)方式。一般以JSONP為傳輸形式的返回文件格式寫(xiě)法如下川蒙,中間為JSON數(shù)據(jù)格式蚜厉,前后有函數(shù)的包裹:
{{callback}}(
{"name":"hikari",
"age":18
});
2.3 實(shí)現(xiàn)方式
- 聲明一個(gè)封裝函數(shù)jsonp,使傳入的url可以自動(dòng)生成一個(gè)隨機(jī)請(qǐng)求名稱的查詢字符串地址畜眨;
function jsonp(url, fn) {
var functionName = 'randomName' + parseInt(Math.random()*100000);
window[functionName] = fn;
var script = document.createElement('script');
script.src = url + '?callback=' + functionName;
document.head.appendChild(script)
}
- 跨域端的數(shù)據(jù)文件xxx.js的內(nèi)容寫(xiě)為JSONP標(biāo)準(zhǔn)格式:
{{callback}}({"name":"hikari", "qb":500});
- 跨域端的服務(wù)器后臺(tái)文件內(nèi)加入獲取查詢字符串的語(yǔ)句昼牛,并將發(fā)送來(lái)的查詢字符串名聲明為callback,在響應(yīng)時(shí)康聂,將callback替換入xxx.js的函數(shù)名贰健。
if(path === '/xxx.js'){
var string = fs.readFileSync('./xxx.js','utf8')
var callback = query.callback;
response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
response.end(string.replace('{{callback}}',callback))
}
- 執(zhí)行jsonp,傳入url和一個(gè)回調(diào)函數(shù)打印出結(jié)果恬汁;
jsonp('http://qq.com:81/xxx.js', function (data) {
console.log('第一次的數(shù)據(jù)');
console.log(data)
});
jsonp('http://qq.com:81/xxx.js', function (data) {
console.log('第二次的數(shù)據(jù)');
console.log(data)
});
- 得到響應(yīng)的數(shù)據(jù)為randomName+一個(gè)5位隨機(jī)數(shù)的執(zhí)行函數(shù)伶椿;
randomName91058({"name":"hikari", "qb":500});
得到的控制臺(tái)信息為
第一次的數(shù)據(jù)
{name: "hikari", qb: 500}
第二次的數(shù)據(jù)
{name: "hikari", qb: 500}
2.4 其他方法
jQuery也為JSONP設(shè)置了對(duì)應(yīng)方法,可以直接調(diào)用氓侧。
$.ajax({
url: 'http://qq.com:81/xxx.js',
type: 'GET',
dataType: 'jsonp',
success: function(data){
console.log('jquery得到的數(shù)據(jù)');
console.log(data)
}
});
得到的響應(yīng)數(shù)據(jù)為:
jQuery21402045766844241943_1502793793916({"name":"hikari", "qb":500});
控制臺(tái)結(jié)果為
jquery得到的數(shù)據(jù)
{name: "hikari", qb: 500}
總結(jié)
CORS策略 和 JSONP策略有何異同脊另?
- JSONP是Script腳本,而CORS策略是由JS發(fā)起的AJAX請(qǐng)求约巷;
- JSONP只能GET數(shù)據(jù)偎痛,AJAX可以請(qǐng)求GET、POST以及各種Methods独郎;
- JSONP安全性有限踩麦,可以任意訪問(wèn),并沒(méi)有同源策略的限制氓癌,而CORS可以由后端指定域名訪問(wèn)谓谦,適合更高級(jí)的管理需求;