阮一峰老师博客 浏览器同源政策及其规避方法:浏览器同源政策及其规避方法 - 阮一峰的网络日志
跨域资源共享 CORS 详解:跨域资源共享 CORS 详解 - 阮一峰的网络日志
目录
4.2 方法二:CORS(Cross-origin resource sharing)跨域资源共享:具体见阮一峰老师的博客
4.3 方法三:跨文档通信 API:window.postMessage()
一、什么是跨域?
由于浏览器同源策略,凡是发送请求url的协议、域名、端口号三者之间任意一个与当前页面地址不同即为跨域。
存在跨域的情况:
-
网络协议不同,如http协议访问https协议。
-
端口不同,如80端口访问8080端口。
-
域名不同,如qianduanblog.com访问baidu.com。
-
子域名不同,如abc.qianduanblog.com访问def.qianduanblog.com。
关于顶级域名、父域名、子域名的补充:
1)顶级域名:域名的最后一个部分,即是域名最后一点之后的字母,例如在http://example.com这个域名中,顶级域是.com
2)父域名和子域名:"http://news.sina.com.cn" 是 http://sina.com.cn的子域名,http://sina.com.cn 就是父域名。
http://sina.com.cn 又可看作是 .http://com.cn 的子域名;而 http://com.cn 又是 .cn 的一个子域名。
注意:跨域不一定是浏览器限制了发起跨域请求,也可能是跨域请求可以正常发起,但是返回的数据被浏览器截获。
二、同源策略?
2.1 什么是同源策略?
同源:两个页面地址中的协议,域名,端口号一致
同源策略:是浏览器的一个安全限制,它阻止了不同【域】之间进行的数据交互
2.2 为什么浏览器要使用同源策略?
同源政策的目的:是为了保证用户信息的安全,防止恶意的网站窃取数据。
如果没有同源限制,在浏览器中的cookie等其他数据可以任意读取,不同域下的DOM任意操作,ajax任意请求其他网站的数据,如果浏览了恶意网站那么就会泄漏这些隐私数据。
设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。
由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。
2.3 安全限制阻止了哪些东西不可以被访问?
- 不能通过ajax请求不同域的数据,
- 不能通过脚本操作不同域下的DOM
- 无法读取不同域下的cookie、localstorage
三、为什么会产生跨域?
因为浏览器的同源政策,就会产生跨域。比如说发送的异步请求是不同的两个源,就比如是不同的的两个端口或者不同的两个协议或者不同的域名。由于浏览器为了安全考虑,就会产生一个同源政策,不是同一个地方出来的是不允许进行交互的。
四、实现跨域的方法?
方法及相应的应用场景
4.1 方法一:jsonp
jsonp是一种借助于 script 标签发送跨域请求的方案。浏览器对script的资源引用没有同源限制(即同源和非同源都可以访问到),script的src属性可以访问网络上的资源,并且script标签可以拿到响应体,获取的数据一般为json格式。
核心思想:网页通过添加一个<script>元素
,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
缺点:只支持get请求,不支持post请求。
注意:script、img、link、iframe都不存在跨域请求的限制 ,并且它们的src请求都是资源文件请求(即get请求)
4.1.1 原生实现的方式
// 1.向服务器api.douban.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
<script src="http://api.douban.com/v2/movie/top250?callback=test"></script>
<script>
// 2.处理服务器返回回调函数的数据
function test(json){
console.log('我被调用了');
console.log(json); // 处理获得的数据
}
</srcipt>
1)通过script中的src访问http://api.douban.com/v2/movie/top250 ,并通过添加参数callback=test 将本地的函数test传给服务器;
2)服务器接收到客户端的请求,给客户端返回数据(返回的数据为json格式);
3)客户端收到数据json,自动调用test这个函数,并且把响应体(JSON数据)当做参数传递过来;
4.1.2 原生实现的过程图解
1)通过script中的src访问 http://127.0.0.1:4000/list ,并通过添加参数callback=func 将本地的函数func传给服务器;
2)服务器接收到客户端的请求,给客户端返回数据(返回的数据为json格式);
3)客户端收到数据data,自动调用方法func(data作为该方法的参数);
4.1.3 在JQuery中使用Ajax 的实现方式
如果是在JQuery中使用Ajax,则只需要在dataType属性中把json改为jsonp即可
用法:
①dataType改为jsonp
②jsonp : "jsonpCallback"————发送到后端实际为http://a.a.com/a/FromServlet?userName=644064&jsonpCallback=jQueryxxx
③后端获取get请求中的jsonpCallback
④构造回调结构
$.ajax({
type : "GET",
url : "http://192.168.10.46/demo/test.jsp", //服务器地址
dataType : "jsonp",//数据类型为jsonp
jsonp : "jsonpCallback",//指定回调函数名,与服务器端接收的一致,并回传回来
success : function(data) {
alert(data["userName"]);
}
});
//后端
String jsonpCallback = request.getParameter("jsonpCallback");
//构造回调函数格式jsonpCallback(数据)
resp.getWriter().println(jsonpCallback+"("+jsonObject.toJSONString()+")");
4.1.4 jsonp的实现原理
Jquery中ajax的核心是通过 XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的 js脚本。浏览器对script的资源引用没有同源限制。
当我们正常地请求一个JSON数据的时候,服务端返回的是一串JSON类型的数据;而我们使用 JSONP模式来请求数据的时候,服务端返回的是一段可执行的JavaScript代码。因为jsonp 跨域的原理就是动态加载<script>的src ,所以我们只能把参数通过url的方式传递,所以jsonp的 type类型只能是get !
对于4.1.3中的实例,
1)jquery 内部会先转化成:http://192.168.10.46/demo/test.jsp?jsonpCallback=jQuery202003573935762227615_1402643146875&action=aaron
2)然后动态加载:
<script type="text/javascript"src="http://192.168.10.46/demo/test.jsp?jsonpCallback= jQuery202003573935762227615_1402643146875&action=aaron"></script>
3)后端就会执行jsonpCallback(传递参数 ),把数据通过实参的形式发送出去。
使用JSONP 模式来请求数据的整个流程:客户端发送一个请求,规定一个可执行的函数名(这里就是 jQuery做了封装的处理,自动帮你生成回调函数并把数据取出来供success属性方法来调用,而不是传递的一个回调句柄),服务器端接受了这个 jsonpCallback函数名,然后把数据通过实参的形式发送出去
(在jquery 源码中, jsonp的实现方式是动态添加<script>标签来调用服务器提供的 js脚本。jquery 会在window对象中加载一个全局的函数,当 <script>代码插入时函数执行,执行完毕后就 <script>会被移除。同时jquery还对非跨域的请求进行了优化,如果这个请求是在同一个域名下那么他就会像正常的 Ajax请求一样工作。)
4.2 方法二:CORS(Cross-origin resource sharing)跨域资源共享:具体见阮一峰老师的博客
阮一峰 跨域资源共享 CORS 详解:跨域资源共享 CORS 详解 - 阮一峰的网络日志
4.2.1 简介
CORS需要浏览器和服务器同时支持。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添
加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
局限性:请求头的源只有两种设置方式:1、* 表示可以接受任何源(设置为*就不允许携带cookie) 2. 具体地址(只能一个源地址)
4.2.2 CROS与JsonP的区别
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET
请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
4.3 方法三:跨文档通信 API:window.postMessage()
调用postMessage方法实现父窗口http://test1.com向子窗口http://test2.com发消息(子窗口同样可以通过该方法发送消息给父窗口)
它可用于解决以下方面的问题:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
- 上面三个场景的跨域数据传递
// 父窗口打开一个子窗口
var openWindow = window.open('http://test2.com', 'title');
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test2.com');
调用message事件,监听对方发送的消息
// 监听 message 消息
window.addEventListener('message', function (e) {
console.log(e.source); // e.source 发送消息的窗口
console.log(e.origin); // e.origin 消息发向的网址
console.log(e.data); // e.data 发送的消息
},false);
4.4 方法四:设置document.domain
因为浏览器是通过document.domain属性来检查两个页面是否同源,因此只要通过设置相同的document.domain,两个页面就可以共享Cookie(此方案仅限主域相同,子域不同的跨域应用场景。)
// 两个页面都设置
document.domain = 'test.com';
4.5 方法五: http proxy (常用)
1)vue2.0配置proxyTable,需要在config文件里面的index.js配置
dev: {
proxyTable: {
'/api': {
// 调用接口/api/hh 相当于 https://baidu.com/api/hh
target: 'https://baidu.com', // 设置你调用的接口域名和端口号 别忘了加http
changeOrigin: true,
pathRewrite: {
// 这里理解成用‘/api’代替target里面的地址,调用接口/api/user 相当于'http://192.168/user'
'^/api': ''
}
}
},
},
2)vue3.0配置proxyTable,需要在新建的vue.config.js文件里面配置
devServer: {
host: 'localhost',
port: 8080,
https: false,
open: true,
// 配置代理
proxy: {
'/api': {
target: 'http://XXX', //里面填写目标接口域名
changeOrigin: true, //开启代理,允许跨域
pathRewrite: {
'^/api': ''//重写接口
}
}
},
},
4.6 方法六:nginx反向代理(不需要前端做)
五、跨域是怎么收集用户数据的?
六、面试问题?
1. 了解跨域吗?有哪些解决的方法? 跨域该如何处理呢,介绍了几种方法以及应用场景?其他的跨域方法讲下,详细讲了 JSONP 方法,为什么jsonp动态创建script标签可以解决跨域?代理服务器方法
2. 项目中有没有遇到过跨域,这是什么,怎么解决的?为什么CORS要区分简单请求和非简单请求?cors跨域的常见字段?CORS在处理复杂请求的时候有什么需要注意的?
CORS,这个就问的比较细,什么是简单请求非简单请求,都是怎么个流程,具体到请求的http头部信息都有问到
3. 讲一讲为什么要跨域, 跨域的同源策略是为了防止哪些攻击?讲一讲 XSS 攻击可能有的攻击场景, 列举防范 XSS 攻击的方式?
4. ajax如何在跨域的情况下携带cookie ?
5. Nignx反向代理是怎么解决跨域问题的?
6. 跨域请求是浏览器的限制还是服务器的限制,跨域发出去能不能到服务器