题目1: 什么是同源策略
同源策略,它是由Netscape提出的一个著名的安全策略。
浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。
如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
现在所有支持JavaScript 的浏览器都会使用这个策略。
所谓同源是指,域名,协议,端口相同。
IE 例外
当涉及到同源策略时,Internet Explorer有两个主要的例外
授信范围(Trust Zones):两个相互之间高度互信的域名,如公司域名(corporate domains),不遵守同源策略的限制。
端口:IE未将端口号加入到同源策略的组成部分之中,因此 http://company.com:81/index.html 和http://company.com/index.html 属于同源并且不受任何限制。
题目2: 什么是跨域?跨域有几种实现形式
跨域就是在不同源的接口进行交互
跨域的实现形式有四种:
jsonp
cors
降域
postMessage
详细见题目5
题目3: JSONP 的原理是什么
JSONP
html中script标签可以引入其他域下的js,比如引入线上的jquery库。利用这个特性,可实现跨域访问接口。需要后端支持
echo $cb . '&&' . $cb . '(' . json_encode($ret) . ')';
定义数据处理函数_fun
创建script标签,src的地址执行后端接口,最后加个参数callback=_fun
服务端在收到请求后,解析参数,计算返还数据,输出 fun(data) 字符串。
fun(data)会放到script标签做为js执行。此时会调用fun函数,将data做为参数。
题目4: CORS是什么
CORS 全称是跨域资源共享(Cross-Origin Resource Sharing),是一种 ajax 跨域请求资源的方式,支持现代浏览器,IE支持10以上。 实现方式很简单,当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该相应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。所以 CORS 的表象是让你觉得它与同源的 ajax 请求没啥区别,代码完全一样。
题目5: 根据视频里的讲解演示三种以上跨域的解决方式 ,
本题模拟跨域,在谷歌浏览器上模拟,设置两个服务器的域名为http://127.0.0.1:2000和http://127.0.0.1:8080,8080向2000端口下的域请求数据
方法1:jsonp
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div class="container">
<div class="news">
<li>中二少时诵诗书</li>
<li>双男力争会师决赛</li>
<li>女排死磕巴西</li>
</div>
<button id="change">换一组</button>
</div>
<script type="text/javascript">
function $(x){
return document.querySelector(x)
}
$('#change').addEventListener('click',function(){
var script=document.createElement('script');
script.src='http://127.0.0.1:2000/page1.json?callback=appendHtml'
document.head.appendChild(script);
})
function appendHtml(data){
var html = '';
for(var i=0; i< data.length; i++){
html += '<li>'+data[i]+'</li>'
}
console.log(html)
$('.news').innerHTML = html;
}
</script>
</body>
</html>
router.js部分
app.get('/page1.json',function(req,res){
var news=[
'aaaaaaaa',
'bbbbbbbb',
'cccccccc',
'ddddddddd',
'eeeeeeeee',
'fffffffff',
'ggggggggg'
]
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;
console.log(cb)
if(cb){
res.send(cb+'('+JSON.stringify(data)+')');
}else{
res.send(data)
console.log(data)
}
//res.header("Access-Control-Allow-Origin",'*')
})
结果如图
json1.png jsonp2.png
方法2:cors
修改一下代码,改成向2000端口发送ajax请求
$('#change').addEventListener('click',function(){
/* var script=document.createElement('script');
script.src='http://127.0.0.1:2000/page1.json?callback=appendHtml'
document.head.appendChild(script);
*/
var xhr=new XMLHttpRequest;
xhr.onload=function(){
appendHtml(xhr.response)
}
xhr.open('GET','http://127.0.0.1:2000/page1.json',true)
xhr.send();
})
得到的结果如图
cors.png现在我在2000端口的服务器上给8080端口的域授权
app.get('/page1.json',function(req,res){
var news=[
'啊啊啊啊啊啊a',
'反反复复付付付付',
'cの额鹅鹅鹅',
'd啛啛喳喳',
'少时诵诗书',
'f啦啦啦啦绿',
'世世代代发我'
]
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;
console.log(cb)
if(cb){
res.send(cb+'('+JSON.stringify(data)+')');
}else{
res.send(data)
console.log(data)
}*/
res.header("Access-Control-Allow-Origin","http://127.0.0.1:8080")
res.send(data)
})
得到的结果如图
cors2.pngcors.png
这样就实现了跨域
方法3postMessege
window.postMessage()方法可以安全地实现跨源通信。通常,当且仅当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机(模数 Document.domain
由两个页面设置为相同的值)。 window.postMessage()方法提供了一种受控机制,以便在正确使用时以安全的方式规避此限制。
window.postMessage()方法被调用时,会在所有页面脚本执行完毕之后(e.g., 在该方法之后设置的事件、之前设置的timeout 事件,etc.)向目标窗口派发一个 MessageEvent
** 消息。 该MessageEvent
消息有四个属性需要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage()方法时调用页面的当前状态; source 属性记录调用 window.postMessage()方法的窗口信息。
postMessage的用法为:otherWindow.postMessage(message, targetOrigin, [transfer]);
第一个参数为:我要发送的data,
第二个参数为:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串""(表示无限制)或者一个URI,在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的orign属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
第三个参数为:Transfer,可选的参数,是一串和message 同时传递的 Transferable
对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
如图 在index设置两个frame元素
index代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<iframe src="1.html" width="300px" height="300px"></iframe>
<iframe src="2.html" width="300px" height="300px"></iframe>
</body>
</html>
frames[0]代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input id="i1" value="" placeholder="1-input"/>
<script type="text/javascript">
function $(x){
return document.querySelector(x)
}
$('#i1').addEventListener('input',function(){
//console.log('this.input.value:'+this.value);
window.parent.frames[1].postMessage(this.value,'*');
// 给本页面父节点的frame[1]发送消息
//console.log(window.frames[0].postMessage);
})
//接受发送的消息,因上面没有指定给自己传输,所以收不到上面的消息
window.addEventListener('message',function(e){
$('#i1').value=e.data;
//console.log('e.data:'+e.data)
})
</script>
</body>
</html>
frame[1]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input id="i2" value="" placeholder="2-input"/>
<script type="text/javascript">
function $(x){
return document.querySelector(x)
}
$('#i2').addEventListener('input',function(){
//console.log('this.input.value:'+this.value);
window.parent.frames[0].postMessage(this.value,'*')
// 给本页面父节点的frame[1]发送消息
})
//接受发送的消息,因上面没有指定给自己传输,所以收不到上面的消息
window.addEventListener('message',function(e){
$('#i2').value=e.data;
})
</script>
</body>
</html>
网友评论