转载自:https://www.jianshu.com/p/827b041be446
https://segmentfault.com/a/1190000009773724
https://segmentfault.com/a/1190000013536703
跨域是什么,为什么会有跨域?跨域的解决方法是什么?常用的是什么?原理是什么?
什么是跨域?
跨域是指从一个域名去请求另一个域名的资源。严格来说,只要协议,域名、端口任何一个不同,就视为跨域。
为什么会出现跨域?
为了安全起见,浏览器设置了一个同源策略,规定:只有域名,端口,协议全部相同,才叫做同源。当页面在执行一个脚本时,会检查访问的资源是否同源,如果不是,就会报错。可是在实际开发中,经常会有跨域加载资源的需求,避免不了跨域请求,所以就出现了跨域。
什么是同源策略及限制?
同源策略是指从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互,这是一个用来隔离潜在恶意文件的的关键的安全机制。不同源之间的交互是被浏览器限制的,为了安全起见。
同源策略限制的具体表现是什么?
(1)cookie、LocalStorage和IndexDB 无法读取
(2)Dom 无法获得
(3)AJAX请求无效(可以发送,但是浏览器会拒绝接受响应)
JS中自带跨域技能的标签是什么 ?
<img/>、<script><script/>以及<iframe>标签,不受同源策略的影响。可以借助这一特点,实现跨域。
说起能跨域的标签,就要提一提常用的跨域方法。
常用的跨域方法是什么?
1、JSONP:服务器端集成script标签返回给客户端,通过javascript callback的形式实现跨域。
<script src="http://localhost:3000/api/orderlist?msg=hello&callback=jsoncb"></script>
原理:利用了script标签,在标签外套了一层壳,利用标签特性达到跨域加载资源的效果。
JSONP由两部分组成,回调函数和数据。
优点:
(1)兼容性好,在多古老的浏览器都能运行。
(2)能直接访问响应文本,支持在浏览器与服务器之间双向通信。
缺点:
(1)只支持GET请求,不支持POST请求;
(2)不够安全。因为JSONP是从其他域中加载代码执行,如果其他域不安全,可能会在响应中带有恶意代码。
(3)不容易确认请求是否失败。
2、CORS -- 跨站资源共享,它是跨域的官方解决方案,升级版的JSONP。
原理是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。默认情况下,请求和响应都不包含cookie信息。
CORS需要浏览器和后端同时支持,实现CORS通信的关键是后端,只要后端实现了CORS,就实现了跨域。浏览器设置Origin字段,服务端设置Access-Control-Allow-Origin 就可以开启CORS,该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。
3、Web Sockets -- 不受同源策略影响。原理是因为它不使用HTTP协议,而使用一种自定义的协议,专门为快速传输少量数据设计。
4、Iframe 注意:在使用iframe进行通信时,只有父窗口与子窗口同源才可以;如果跨域,无法拿到对方DOM.
// 现有两个页面,分别在两个域下。a页面想要向http://127.0.0.1:3001发送ajax请求,需要借助http://127.0.0.1:3001下的b页面。
http://127.0.0.1:3000/a.html
http://127.0.0.1:3001/b.html
当a页面中有一个b页面的iframe时,两个页面共享window.name。在b页面与拿到数据后赋值给window.name。可以将b页面的location.href转为http://127.0.0.1:3000下的c页面,(相当于同一个域下的c页面内嵌在a页面中) 由c页面调用a页面的回调方法。
// a.html
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <iframe src="http://127.0.0.1:3001/b.html"></iframe> <script> function print(data) { console.log(data); } </script> </body> </html>
// b.html
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="http://code.jquery.com/jquery-3.3.1.min.js"></script> </head> <body> <script> $.ajax({ url: 'data.json' }).done(data => { window.name = JSON.stringify(data); location.href = 'http://localhost:3000/c.html'; }) </script> </body> </html>
// c.html
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> window.parent.print(JSON.parse(window.name)); </script> </body> </html>
子窗口内获取父窗口DOM元素的方法:window.parent / window.top.
------------------------------------------------------------------------------------------------
服务器端:
如果你要自己实现 CORS 功能,注意遵守下面的准则:
如果是写死的 Access-Control-Allow-Origin(*或者某一特定的域名)
,一定不要加 Vary: Origin;
如果是根据 Origin
请求头动态计算出的(*.taobao.com) Access-Control-Allow-Origin
,一定要始终加上Vary: Origin
,即便在没有 Origin
请求头的情况(<img>和<script>)。