同源策略的基本概念
同源策略简介:1995年,同源政策由Netscape引入浏览器,目前,所有的浏览器都实行这个政策.
同源:指的是协议,域名,端口号相同都称为是同源网站
同源策略的目的
同源策略的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据
同源策略的限制范围
随着互联网的发展,'同源策略'越来越严格,目前,如果非同源,下面的行为将会受到限制:
- Cookie、LocalStorage 和 IndexDB 无法读取。
- DOM 无法获得。
- AJAX 请求在浏览器端有跨域限制
虽然这些限制是保证了数据的安全性,但是同时他也给开发者带来了一定的困扰,由于网络的不断发展,不同公司的业务更加庞大,所需要的技术也更加精准,所以各个部门都会有自己的域名,这时就会出现跨域现象
解决跨域的方案
方法一JSONP:
JSONP(JSON with Padding)、可用于解决主流浏览器的跨域数据访问的问题。
由于DOM中的src属性支持跨域,所以JSONP的原理也就是利用了script标签中的src来实现跨域的,除了script标签之外,还有img和link标签.
<!--不受同源策略限制的标签-->
<img src="http://www.api.com/1.jpg" alt="">
<link rel="stylesheet" href="http://www.api.com/1.css">
<script src="http://www.api.com/1.js"></script>
JSONP实现代码
<script>
var inp = document.getElementById('inp');
var ul = document.querySelector('ul');
function suggest_so(data){
// console.log(data)
ul.innerHTML =''
var {result} = data;
result.forEach(function(ele){
var li = document.createElement('li');
li.innerHTML = ele.word;
ul.appendChild(li)
})
}
inp.oninput = function(){
if(document.getElementsByClassName('ss').length>0){
document.getElementsByClassName('ss')[0].remove()
}
var val = inp.value;
// 通过动态创建src属性实现
var jsonp = document.createElement('script');
jsonp.src = 'https://sug.so.360.cn/suggest?callback=suggest_so&encodein=utf-8&encodeout=utf-8&format=json&fields=word&word='+val;
jsonp.className = 'ss';
document.body.appendChild(jsonp)
}
</script>
在script属性中有一个src属性,里面有一个callback回调函数,这个回调函数是在src里面的,他的作用就是当响应来到时,应该在页面中调用的函数,而数据就是传入回调函数的JSON数据.
JSONP实现原理
- 1)利用了script的src属性支持跨域访问
- 2)script标签的后面需要写上需要请求的页面,发送了一个方法的名字到服务器.
- 3)服务器接收到名字之后,拼接一个方法的调用在参数中传入需要给浏览器的数据
- 4)返回浏览器,浏览器把他们当js解析,没有跨域问题,从服务器获取数据
原理:服务端返回一个定义好的js函数的调用,并且将服务器的数据以该函数参数的形式传递过来,这个方法需要前后端配合.
jQuery实现跨域
$(function(){
$('#inp').on('input',function(){
$.ajax({
url:'https://sug.so.360.cn/suggest?callback=suggest_so&encodein=utf-8&encodeout=utf-8&format=json&fields=word&word='+$(this).val(),
dataType:'jsonp',
jsonpCallback:'suggest_so',
success:function(data){
var {result} = data;
var str = template('tpl',{result});
$('ul').html(str)
}
})
})
})
这里用的是dataType和jsonpCallback,来实现跨域
JSONP的缺点:
- 1它只支持GET请求而不支持POST等其它类型的HTTP请求
- 2它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
- 3 jsonp在调用失败的时候不会返回各种HTTP状态码。
- 4缺点是安全性。万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。那么结果是什么?所有调用这个 jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下…所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。
只支持get请求的原因:
由于script标签只能发送get请求 所以jsonp不支持post方式的跨域
方法二CORS: 具体流程: 浏览器发送跨域请求
服务器端收到一个跨域请求后,在响应头中添加Access-Control-Allow-Origin Header资源权限配置。发送响应
浏览器收到响应后,查看是否设置了header('Access-Control-Allow-Origin:请求源域名或者*');
如果当前域已经得到授权,则将结果返回给JavaScript。否则浏览器忽略此次响应。
app.get('/getmsg',(req,res)=>{
let msg =[{name:'zs',age:18,gender:'boy'}];
res.header('Access-Control-Allow-Origin',"*")
res.json({msg:'ok',code:200,data:msg})
})
这种方法虽然简单,但是这种方法是h5新出的,所以这种方法有兼容性问题
方法三Nginx:
同源策略只是针对的浏览器端,所以这里通过服务端反向代理的方式实现跨域, Nginx解决跨域问题通过Nginx反向代理将对真实服务器的请求转移到本机服务器来避免浏览器的"同源策略限制"。
方法四:
window.name+iframe 需要目标服务器响应window.name。
方法五:
window.location.hash+iframe 同样需要目标服务器作处理。
方法六:
html5的 postMessage+ifrme 这个也是需要目标服务器或者说是目标页面写一个postMessage,主要侧重于前端通讯。
HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。
这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。
举例来说,父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法就可以了。
var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');
postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。
子窗口向父窗口发送消息的写法类似。
window.opener.postMessage('Nice to see you', 'http://aaa.com');
方法七:
Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 Cookie。
举例来说,A网页是http://w1.example.com/a.html,B网页是http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享Cookie。
document.domain = 'example.com';
现在,A网页通过脚本设置一个 Cookie。
document.cookie = "test1=hello";
B网页就可以读到这个 Cookie。
var allCookie = document.cookie;
注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法,规避同源政策,