1,什么是同源策略
同源策略:
浏览器处于安全方面的考虑,只允许与本域下的接口交互,不同源的客户端脚本在没有明确授权的情况下,不能读取对方的资源。
- 同协议:(http、file、shh、https、tel、ftp...)以上协议必须相同;
- 同域名:第一个
//
到第二个/
之间的部分必须相同; - 同端口:一般为80,具体看设置。
以上三条都相同则为同源。
2,什么是跨域?跨域有几种实现形式
跨域:
在使用ajax向后台请求数据时,如果接口域名不相同,即为跨域。
换句话说,允许不同域的接口进行交互即为跨域。跨域实现形式:
JSONP
CORS
降域
postMessage
3,JSONP 的原理是什么
应用中我们发现,使用<script>
标签引用链接不会出现跨域问题,因此,可以采用这种方式跨域。<script src='链接 '></script>
。服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
4,CORS是什么
- CORS:跨域资源共享(Cross-origin resource sharing)
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。 - 实现方式:
当你使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该相应头中是否包含Origin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。
5,根据视频里的讲解演示三种以上跨域的解决方式
- 方法一:JSONP
- 优势:
- 不需要AJAX,只需要通过script标签即可完成向后台发送请求并获取数据;
- 劣势:
- 需要后台支持输出指定格式的内容,比如下面例子中的函数名需要后台进行配合;
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>在北大听讲座</li>
<li>统计陷阱</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';
//当点击按钮时,会在head中生成一个script标签,并下载标签中引用的链接内容。
//返回的是appendhtml(内容),这个会被函数appendhtml执行,放在html上。
document.head.appendChild(script);
document.head.removeChild(script);
})
//为了避免生成太多script标签,生成之后立刻删除,但是内容已经下载,不会影响。
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>
后台端:
app.get('/getNews', function(req, res) {
var news = [
"身边的逻辑学",
'牛奶可乐经济学',
'看见',
'论中国',
'乌合之众',
'哲学的慰藉'
]
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的内容(函数名称),包装之后返回给html。
方法二:CORS
优势:
整个过程无需用户参与,完全由浏览器自己完成;
只需要在后台加入响应头即可,不需要对ajax进行复杂变换;
劣势:
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>在北大听讲座</li>
<li>统计陷阱</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>
后台端:
app.get('/getNews', function(req, res) {
var news = [
"身边的逻辑学",
'牛奶可乐经济学',
'看见',
'论中国',
'乌合之众',
'哲学的慰藉'
]
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,因为后台端是在b.har.com域下
res.header("Access-Control-Allow-Origin","*");
res.send(data);
});
方法三:降域
优势:
代码超级简单,只需一个命令就轻松搞定;
劣势:
只能在拥有相同父域名下才可以使用;
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>使用降域来实现跨域</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>使用降域来实现跨域</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
- 优势:
- 域名完全不相同也没关系;
- 劣势:
- 操作真心复杂;
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来实现跨域</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来实现跨域</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>