什么是同源策略
-
什么是同源
简单点儿理解字面的意思就是“同一源头”这也就意味着两边:- 协议必须要一样,要么都是http,要么都是https等等,其他的协议如file,ssh....都是一个道理,也都要一样才行
- 第二个就是域名要一样,要注意到http://www.a.com与http://a.com是两个不同的网站
- 端口也要一样才行。
要注意到http://www.a.com 与 http://www.a.com:8080 不是同源的因为前者的端口号是80端口
需要留心的是:对于当前页面来说页面存放的 JS 文件的域不重要,重要的是加载该 JS 页面所在什么域
-
简单说下,为什么要有“同源策略”
本来的只要服务器愿意提供接口,不同源的双方是可以进行通信的,但是浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。
什么是跨域?跨域有几种实现形式
- 什么是跨域
允许不同域的接口,进行通信交互就叫做跨域啦 - 跨域有几种实现形式
- JSONP
- CORS 兼容问题要考虑
- 降域
- postMessage
JSONP 的原理是什么
后端程序员开放一个数据接口,前端利用<script>
标签引入接口后,就可以向后端发送请求了,发送请求的时候传入前端页面处理数据的函数(callback=funname),后端接收到前端的请求之后,把数据返回给前端页面,前端接收到返回数据后用已经写好的方法展现处理数据
例子:
//这个端口一般是用代码拼装起来的
<script src="http://a.com/gerData?callback=showData"></script>
//前端的话 写一个同名的处理函数
function showData (data){
do something
}
CORS是什么
cors(Cross-Origin Resourse Sharing跨域源资源共享)利用浏览器对于不同源的请求,会在请求页面的源信息添加一个origin等于当前请求页面的源信息。
在服务器端,返回数据的时候,设置响应头的Access-Control-Allow-Origin等于对应的页面源信息,浏览器发现请求头的origin和服务器返回的响应头中的值对应上了,就发送了数据,如果不匹配,请求就会被驳回,没有得到响应的数据。
这个方法只能在IE10以上使用,主要的变动是在后端,因为语言语法的问题,响应头的写法各有不同。
app.get('路径', function(req, res) {
//对响应的头部信息进行设置 如果第二个参数为*,就代表谁都可以拿到返回数据啦
res.header('Access-Control-Allow-Origin','http://a.com');
res.send(resData);
});
根据视频里的讲解演示三种以上跨域的解决方式 ,写成博客
三种跨域方式的展示
- 第一种JSONP形式
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>jsonp的跨域方法-杨晨健</title>
</head>
<body>
<div class="container">
<ul class="news">
<li>NBA-8:00视频直播勇士vs热火 9:00火箭出战</li>
<li>鲁媒评CBA本土一哥之争:易帝退位 丁神登基</li>
<li>四人梅开二度上港热身10-0 辽足签两澳洲国脚</li>
</ul>
<button class="change">换一组</button>
</div>
<script>
$('.change').addEventListener('click', function(){
var script = document.createElement('script');
script.src = 'http://b.aaa.com:8080/getNews?callback=appendHtml';//跨域的地址其中callback很重要
document.head.appendChild(script);//添加到页面的头部标签里面
document.head.removeChild(script);//用完就删,保持整洁
})
//对后端给到的数据进行一个前端处理 方法名字要和回调函数的名字一样才行
function appendHtml(news){
var html = '';
for( var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>';
}
$('.news').innerHTML = html;
}
function $(id){
return document.querySelector(id);
}
/* ---------------------------router.js---------------------- */
app.get('/getNews', function(req, res){
var news = [
"第11日前瞻:中国冲击4金 博尔特再战200米羽球",
"正直播柴飚/洪炜出战 男双力争会师决赛",
"女排将死磕巴西!郎平安排男陪练模仿对方核心",
"没有中国选手和巨星的110米栏 我们还看吗?",
"中英上演奥运金牌大战",
"博彩赔率挺中国夺回第二纽约时报:中国因对手服禁药而丢失的奖牌最多",
"最“出柜”奥运?同性之爱闪耀里约",
"下跪拜谢与洪荒之力一样 都是真情流露"
]
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;
if(cb){
res.send(cb + '('+ JSON.stringify(data) + ')');
}else{
res.send(data);
}
})
</script>
</body>
</html>
- 第二种方式 cros
//前端的话 就像ajax请求那么写就好 没有太大变化,主要是后端发生的改变
<!DOCTYPE html>
<html lang=“zh-cn”>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="container">
<ul class="news">
<li>NBA-8:00视频直播勇士vs热火 9:00火箭出战</li>
<li>鲁媒评CBA本土一哥之争:易帝退位 丁神登基</li>
<li>四人梅开二度上港热身10-0 辽足签两澳洲国脚</li>
</ul>
<button class="change">换一组</button>
</div>
<script>
$('.change').addEventListener('click',function(){
var xhr = new XMLHttpRequest();
xhr.open('get','http://b.aaa.com:8080/getNews',true);
xhr.send();
xhr.onreadystatechange = function(){
if (xhr.readyState === 4 && xhr.status === 200) {
appendHtml(JSON.parse(xhr.responseText));
}
}
window.xhr = xhr;
})
function appendHtml(news){
var html = '';
for( var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>';
}
console.log(html);
$('.news').innerHTML = html;
}
function $(id){
return document.querySelector(id);
}
/*------------------------router.js----------------------------*/
app.get('/getNews', function(req, res){
var news = [
"第11日前瞻:中国冲击4金 博尔特再战200米羽球",
"正直播柴飚/洪炜出战 男双力争会师决赛",
"女排将死磕巴西!郎平安排男陪练模仿对方核心",
"没有中国选手和巨星的110米栏 我们还看吗?",
"中英上演奥运金牌大战",
"博彩赔率挺中国夺回第二纽约时报:中国因对手服禁药而丢失的奖牌最多",
"最“出柜”奥运?同性之爱闪耀里约",
"下跪拜谢与洪荒之力一样 都是真情流露"
]
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.header("Access-Control-Allow-Orgin","b.aaa.com:8080”);//这句话很重要是cros跨域方法的重要支撑,如果第二个参数填写*的话 那就是如何域名访问,后端都给数据,同时也要意识到这个方法的话只能在ie10以上的浏览器中使用
res.send(data);
})
</script>
</body>
</html>
- 通过降域的方式来实现跨域
//这种方法局限性很大,相对来说比较小众,跨域的双方的主域名必须一致才可以
/-------------------a.yangchenjian.com---------------------------/
<!DOCTYPE html>
<html lang=“zh-cn">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
省略。。。
</style>
</head>
<body>
<div class="ct">
<h1>使用降域实现跨域</h1>
<div class="main">
<input type="text" placeholder="http://a.yangchenjian.com:8080/a.html">
</div>
<iframe src="http://b.yangchenjian.com:8080/b.html" frameborder="0"></iframe>
</div>
<script>
document.querySelector('.main input').addEventListener('input', function() {
console.log(this.value);//打印出监听a的输入内容
window.frames[0].document.querySelector('input').value = this.value;//选中iframe把a的输入内容給b
})
document.domain = "yangchenjian.com" //这个是非常重要的一步将2级域名降成主域名
</script>
</body>
</html>
/-------------------b.yangchenjian.com---------------------------/
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
省略。。。。
</style>
</head>
<body>
<input id="input" type="text" placeholder="http://b.yangchenjian.com:8080/b.html">
<script>
document.querySelector('#input').addEventListener('input', function() {
console.log(this.value);
window.parent.document.querySelector('input').value = this.value;//把自己的值也传递给自己的父窗口
})
document.domain = 'yangchenjian.com';
</script>
</body>
</html>