1评架,什么是同源策略
同源策略:
瀏覽器處于安全方面的考慮,只允許與本域下的接口交互炕泳,不同源的客戶(hù)端腳本在沒(méi)有明確授權(quán)的情況下纵诞,不能讀取對(duì)方的資源。
- 同協(xié)議:(http培遵、file浙芙、shh、https籽腕、tel嗡呼、ftp...)以上協(xié)議必須相同;
- 同域名:第一個(gè)
//
到第二個(gè)/
之間的部分必須相同皇耗; - 同端口:一般為80南窗,具體看設(shè)置。
以上三條都相同則為同源廊宪。
2矾瘾,什么是跨域?跨域有幾種實(shí)現(xiàn)形式
跨域:
在使用ajax向后臺(tái)請(qǐng)求數(shù)據(jù)時(shí)箭启,如果接口域名不相同壕翩,即為跨域。
換句話(huà)說(shuō)傅寡,允許不同域的接口進(jìn)行交互即為跨域放妈。跨域?qū)崿F(xiàn)形式:
JSONP
CORS
降域
postMessage
3,JSONP 的原理是什么
應(yīng)用中我們發(fā)現(xiàn)荐操,使用<script>
標(biāo)簽引用鏈接不會(huì)出現(xiàn)跨域問(wèn)題芜抒,因此,可以采用這種方式跨域托启。<script src='鏈接 '></script>
宅倒。服務(wù)端不再返回JSON格式的數(shù)據(jù),而是返回一段調(diào)用某個(gè)函數(shù)的js代碼屯耸,在src中進(jìn)行了調(diào)用拐迁,這樣實(shí)現(xiàn)了跨域。
4疗绣,CORS是什么
- CORS:跨域資源共享(Cross-origin resource sharing)
它允許瀏覽器向跨源服務(wù)器线召,發(fā)出XMLHttpRequest請(qǐng)求,從而克服了AJAX只能同源使用的限制多矮。 - 實(shí)現(xiàn)方式:
當(dāng)你使用XMLHttpRequest發(fā)送請(qǐng)求時(shí)缓淹,瀏覽器發(fā)現(xiàn)該請(qǐng)求不符合同源策略,會(huì)給該請(qǐng)求加一個(gè)請(qǐng)求頭:Origin,后臺(tái)進(jìn)行一系列處理讯壶,如果確定接受請(qǐng)求則在返回結(jié)果中加入一個(gè)響應(yīng)頭:Access-Control-Allow-Origin; 瀏覽器判斷該相應(yīng)頭中是否包含Origin的值料仗,如果有則瀏覽器會(huì)處理響應(yīng),我們就可以拿到響應(yīng)數(shù)據(jù)鹏溯,如果不包含瀏覽器直接駁回罢维,這時(shí)我們無(wú)法拿到響應(yīng)數(shù)據(jù)淹仑。
5丙挽,根據(jù)視頻里的講解演示三種以上跨域的解決方式
- 方法一:JSONP
- 優(yōu)勢(shì):
- 不需要AJAX,只需要通過(guò)script標(biāo)簽即可完成向后臺(tái)發(fā)送請(qǐng)求并獲取數(shù)據(jù)匀借;
- 劣勢(shì):
- 需要后臺(tái)支持輸出指定格式的內(nèi)容颜阐,比如下面例子中的函數(shù)名需要后臺(tái)進(jìn)行配合;
html端:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>新聞加載example</title>
<style media="screen">
.newsFrame{
margin: 0 auto;
}
</style>
</head>
<body>
<div class="newsFrame">
<ul class="content">
<li>在北大聽(tīng)講座</li>
<li>統(tǒng)計(jì)陷阱</li>
<li>淺薄</li>
</ul>
<button class="btn">換一批</button>
</div>
<script type="text/javascript">
$('.btn').addEventListener('click',function(){
var script = document.createElement('script');
script.src='http://b.har.com:8080/getNews?callback=appendhtml';
//當(dāng)點(diǎn)擊按鈕時(shí)吓肋,會(huì)在head中生成一個(gè)script標(biāo)簽凳怨,并下載標(biāo)簽中引用的鏈接內(nèi)容。
//返回的是appendhtml(內(nèi)容)是鬼,這個(gè)會(huì)被函數(shù)appendhtml執(zhí)行肤舞,放在html上。
document.head.appendChild(script);
document.head.removeChild(script);
})
//為了避免生成太多script標(biāo)簽均蜜,生成之后立刻刪除李剖,但是內(nèi)容已經(jīng)下載,不會(huì)影響囤耳。
function appendhtml(news){
var html = '';
for(var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>'
}
console.log(html)
$('.content').innerHTML = html
}
function $(id){
return document.querySelector(id)
}
</script>
</body>
</html>
后臺(tái)端:
app.get('/getNews', function(req, res) {
var news = [
"身邊的邏輯學(xué)",
'牛奶可樂(lè)經(jīng)濟(jì)學(xué)',
'看見(jiàn)',
'論中國(guó)',
'烏合之眾',
'哲學(xué)的慰藉'
]
var data = [];
for(var i=0; i<3; i++){
var index = parseInt(Math.random()*news.length);
data.push(news[index]);
news.splice(index,1);
}
var cb = req.query.callback;
res.send( cb + '(' + JSON.stringify(data) + ')' );
});
//獲取callback的內(nèi)容(函數(shù)名稱(chēng))篙顺,包裝之后返回給html。
方法二:CORS
優(yōu)勢(shì):
整個(gè)過(guò)程無(wú)需用戶(hù)參與充择,完全由瀏覽器自己完成德玫;
只需要在后臺(tái)加入響應(yīng)頭即可,不需要對(duì)ajax進(jìn)行復(fù)雜變換椎麦;
劣勢(shì):
HTML端:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>新聞加載example</title>
<style media="screen">
.newsFrame{
margin: 0 auto;
}
</style>
</head>
<body>
<div class="newsFrame">
<ul class="content">
<li>在北大聽(tīng)講座</li>
<li>統(tǒng)計(jì)陷阱</li>
<li>淺薄</li>
</ul>
<button class="btn">換一批</button>
</div>
<script type="text/javascript">
$('.btn').addEventListener('click',function(){
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('get','http://b.har.com:8080/getNews',true);
xmlhttp.send();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState==4 && xmlhttp.status==200){
appendhtml(JSON.parse(xmlhttp.responseText));
}
}
})
function appendhtml(news){
var html = '';
for(var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>'
}
console.log(html)
$('.content').innerHTML = html
}
function $(id){
return document.querySelector(id)
}
</script>
</body>
</html>
后臺(tái)端:
app.get('/getNews', function(req, res) {
var news = [
"身邊的邏輯學(xué)",
'牛奶可樂(lè)經(jīng)濟(jì)學(xué)',
'看見(jiàn)',
'論中國(guó)',
'烏合之眾',
'哲學(xué)的慰藉'
]
var data = [];
for(var i=0; i<3; i++){
var index = parseInt(Math.random()*news.length);
data.push(news[index]);
news.splice(index,1);
}
// res.head('Access-Control-Allow-Origin','http://a.har.com:8080')
//注意這里是a.har.com:8080宰僧,因?yàn)楹笈_(tái)端是在b.har.com域下
res.header("Access-Control-Allow-Origin","*");
res.send(data);
});
方法三:降域
優(yōu)勢(shì):
代碼超級(jí)簡(jiǎn)單,只需一個(gè)命令就輕松搞定观挎;
劣勢(shì):
只能在擁有相同父域名下才可以使用琴儿;
a.har.com端:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>降域test</title>
<style media="screen">
.main{
border: 1px solid #ccc;
width:500px;
height: 500px;
display: inline-block;
position: absolute;
top:10px;
left:10px;
}
iframe{
border: 1px dashed #ccc;
width:500px;
height:500px;
margin-left: 100px;
position: absolute;
top:10px;
left:450px;
}
</style>
</head>
<body>
<div class="ct">
<div class="main">
<h1>使用降域來(lái)實(shí)現(xiàn)跨域</h1>
<input type="text" class="content" placeholder="http://a.har.com:8080">
</div>
<iframe src="http://b.har.com:8080/jiangyu2.html" frameborder="0"></iframe>
</div>
<script type="text/javascript">
document.querySelector('.main input').addEventListener('input',function(){
console.log(this.value);
window.frames[0].document.querySelector('input').value = this.value;
})
document.domain = 'har.com';
//降域的命令键兜;
</script>
</body>
</html>
b.har.com端:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>降域test2</title>
<style media="screen">
</style>
</head>
<body>
<div class="ct">
<h1>使用降域來(lái)實(shí)現(xiàn)跨域</h1>
<div class="main">
<input type="text" class="content" placeholder="http://a.har.com:8080">
</div>
</div>
<script type="text/javascript">
document.querySelector('.main input').addEventListener('input',function(){
window.parent.document.querySelector('input').value = this.value;
})
document.domain = 'har.com';
//降域的命令凤类;
</script>
</body>
</html>
-方法四:postMassage
- 優(yōu)勢(shì):
- 域名完全不相同也沒(méi)關(guān)系;
- 劣勢(shì):
- 操作真心復(fù)雜普气;
a.har.com:8080/postMessage端:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>降域test</title>
<style media="screen">
.main{
border: 1px solid #ccc;
width:500px;
height: 500px;
display: inline-block;
position: absolute;
top:10px;
left:10px;
}
iframe{
border: 1px dashed #ccc;
width:500px;
height:500px;
margin-left: 100px;
position: absolute;
top:10px;
left:450px;
}
</style>
</head>
<body>
<div class="ct">
<div class="main">
<h1>使用postMessage來(lái)實(shí)現(xiàn)跨域</h1>
<input type="text" class="content" placeholder="http://a.har.com:8080">
</div>
<iframe src="http://b.har.com:8080/postMessage2.html" frameborder="0"></iframe>
</div>
<script type="text/javascript">
document.querySelector('.main input').addEventListener('input',function(){
console.log(this.value);
window.frames[0].postMessage(this.value,'*');
})
window.addEventListener('message',function(e){
document.querySelector('.main input').value = e.data;
})
</script>
</body>
</html>
b.har.com:8080/postMessage2端:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>降域test2</title>
<style media="screen">
</style>
</head>
<body>
<div class="ct">
<h1>使用postMessage來(lái)實(shí)現(xiàn)跨域</h1>
<div class="main">
<input type="text" class="content" placeholder="http://a.har.com:8080">
</div>
</div>
<script type="text/javascript">
document.querySelector('.main input').addEventListener('input',function(){
window.parent.postMessage(this.value,'*');
})
window.addEventListener('message',function(e){
document.querySelector('.main input').value = e.data;
console.log(e.data);
})
</script>
</body>
</html>