什么是跨域?
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。
为什么会跨域?
呐,说起跨域就不得不提一下同源策略,那什么是同源策略呢?
同源策略(浏览器提供的一种安全的运行环境)
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制
同源策略限制以下几种行为:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 Js对象无法获得
- AJAX 请求不能发送
倘若没有了同源策略限制的接口请求,很容易受到 CSRF
攻击和 XSS
攻击
倘若没有了同源策略限制的Dom查询,会很容易被窃取信息
所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
什么场景会跨域?
要说起跨域产生的场景,就不得不要了解一下URL地址了
http://username:password@www.kuayu.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name
一个完整URL包含一下几部分:
- 协议部分
protocol
:该URL的协议部分为http
,这代表网页使用的是HTTP协议。在Internet中可以使用多种协议,如HTTPS
,FTP
,FILE
等。在HTTP
后面的//
为分隔符 - 验证
authentication
:该URL的验证部分为username:password
,这种 URL 是不赞成使用的。原因看这里O(∩_∩)O - 域名部分(主机地址)
hostname
:该URL的域名部分为www.kuayu.com
,一个URL中,也可以使用IP地址作为域名使用 - 端口部分
port
:该URL的端口部分为8080
,跟在域名后面的是端口,域名和端口之间使用:
作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口80 - 虚拟目录部分 :该URL的虚拟目录为
/news/
,从域名后的第一个/
开始到最后一个/
为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分。 - 路径部分
pathname
: 该URL的路径部分为index.asp
,从域名后的最后一个/
开始到?
为止,是文件名部分,如果没有?
,则是从域名后的最后一个/
开始到#
为止,是文件部分,如果没有?
和#
,那么从域名后的最后一个/
开始到结束,都是文件名部分。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名 - 查询(参数)部分
serarch
: 该URL的查询部分为boardID=5&ID=24618&page=1
,从?
开始到#
为止之间的部分为参数部分,又称搜索部分、查询部分。参数可以允许有多个参数,参数与参数之间用&
作为分隔符。 - 锚部分 : 该URL的锚部分为
name
,从“#”开始到最后,都是锚部分。锚部分也不是一个URL必须的部分
好了,话题拉回来,让我们来看一下跨域的场景
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.domain.com/a.js | 同一域名,不同文件或路径 | 允许 |
http://www.domain.com/b.js | ||
http://www.domain.com/lab/c.js | ||
http://www.domain.com:8000/a.js | 同一域名,不同端口 | 不允许 |
http://www.domain.com/b.js | ||
http://www.domain.com/a.js | 同一域名,不同协议 | 不允许 |
https://www.domain.com/b.js | ||
http://www.domain.com/a.js | 域名和域名对应相同ip | 不允许 |
http://192.168.4.12/b.js | ||
http://www.domain.com/a.js | 主域相同,子域不同 | 不允许 |
http://x.domain.com/b.js | ||
http://domain.com/c.js | ||
http://www.domain1.com/a.js | 不同域名 | 不允许 |
http://www.domain2.com/b.js |
怎么解决跨域?
1. jsonp
JSONP:JSON
的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com
的网页无法与不是 server1.example.com
的服务器沟通,而 HTML
的 <script>
元素是一个例外。利用 <script>
元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON
资料,而这种使用模式就是所谓的 JSONP
。用 JSONP
抓到的资料并不是 JSON
,而是任意的 java script
,用 java script
直译器执行而不是用 JSON
解析器解析。 - 选自百度百科
前端代码:
$('#btn').click(function(){
var frame = document.createElement('script');
frame.src = 'http://localhost:5000/jsonp?name=aaron&age=18&callback=query';
$('body').append(frame);
});
function query(res){
console.log(res.message+res.name+'你已经'+res.age+'岁了');
}
后端代码:
router.get('/jsonp', (req, res) => {
let {name,age,callback} = req.query;
let data = {message:'success',name,age};
data = JSON.stringify(data);
res.end(`${callback}(${data})`);
});
jsonp缺点:只能实现get一种请求。
2. document.domain + iframe
此方案仅限主域相同,子域不同的跨域应用场景。
实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
<!--父窗口:(http://www.domain.com/a.html)-->
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
document.domain = 'domain.com';
var user = 'admin';
</script>
<!--子窗口:(http://child.domain.com/b.html)-->
<script>
document.domain = 'domain.com';
// 获取父窗口中变量
al