关于跨域以及解决思路
本章内容目录:
一、跨域相关概念的理解
二、跨域产生的原因
三、跨域的几种解决方案
一、跨域相关概念的理解
首先先了解以下几个概念:
- "同源策略"
同源策略,相同来源的策略。它是浏览器的一种约定,为了安全,浏览器页面禁止来自不同源的网页或脚本加载。
- "同源"和"跨域"
同源,即协议,域名、端口都相同。
跨域,即协议、域名、端口有任何一个不相同。和同源的概念相反。
我们都知道URL一般都是由协议、域名、端口、路径构成。
A页面访问B页面,如果这两个页面URl的协议、域名、端口都相同,则表示他们同源,可以访问;反之,如果协议、域名、端口三个中有任何一个不相同,就表示跨域,访问被拒绝。
如:http://leaf.com/test/index.html访问以下URL进行同源策略检查,查看是否跨域:
URL | 是否跨域 | 理由 |
---|---|---|
http://leaf.com/test2/index.html | 没有跨域 | 其他相同,只是路径不同 |
http://leaf.com/test/index2.html | 没有跨域 | 其他相同,只是路径不同 |
https://leaf.com/test/index.html | 跨域了 | 协议不同 |
http://leaf.com:8080/test/index.html | 跨域了 | 端口不同 |
http://leafice.com/test/index.html | 跨域了 | 域名不同 |
- 有哪些不受浏览器同源策略影响的脚本或标签?
有src属性的标签是可以加载跨域资源的,不受浏览器同源策略的限制,如:<script>、<img>、<iframe>、<link>等。
一个页面当中,js脚本、css样式文件、img图片的资源是可以和页面不同源的;它们可能是某个CDN地址。如我们平常引用的BootCDN:
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
二、跨域产生的原因
- 浏览器“同源策略”的限制
(使得不同域名的两个页面之间不能相互访问) - 请求方式Type为XHR请求
(如果发送的不是XHR请求,json、js就算是跨域也不会报错) - 请求方和服务方不同源,即跨域
(协议、域名、端口号有任何一项不同)
只要满足以上的三个条件才有可能产生跨域。
三、跨域的几种解决方案
根据跨域产生的三个原因对应有以下三种解决思路:
1、禁止浏览器校验,关闭"同源策略"(不推荐)
指定参数禁止浏览器校验:
--disable-web-security --user-data-dir
(有时候可以做本地测试跨域使用,不依赖服务端)
步骤:(针对chrome)
1、必须关掉chrome打开的所有页面,否则不生效;
2、新建chremo的快捷方式,并右键选择“属性”打开:
3、在“目标”处,添加
--disable-web-security --user-data-dir
,最后应用保存,添加后如图:image.png
4、打开新快捷方式,会显示提示文案:如下图所示,说明已经禁止了浏览器的“同源策略”,输入你的本地预览地址,应该可跨域了:
image.png
缺点:需要客户端改动
2、JSONP(常用跨域方案,需掌握)
在页面中使用XMLHttpRequest请求不同域上的数据是不可以的,但是在页面上引入不同域的JS脚本确实允许的。(上边说了<script>不受浏览器同源策略的限制)
(1)JSONP是什么?
一种非官方协议;
允许用户传递一个callback参数给服务端;
(2)JSONP跨域的实现原理?
由于 script 标签不受浏览器同源策略的影响,允许跨域引用资源。因此:
JSONP实现原理:就是前端请求后台包装好的一段JSON数据,后台会把数据放在一个callback函数中,返回一个JS文件,前端只需动态引入这个JS文件,再去调用callback函数就可以访问数据了。
注意:
请求完之后这个JS就会被销毁,可以通过控制台打断点的方式验证。
具体的实现思路步骤:
①JSONP发送请求时URL会添加一个查询字符串默认callback指定回调函数名,如参数callback=a指定回调函数的名为a;
(callback=a的作用就是让后端知道前端调用函数的函数名,可以通过ajax中的jsonp指定查询字符串(默认callback)、jsonpCallback指定回调函数名)
如:
<script>
function fetchData() {
$.ajax({
type: "GET",
url: "xxxx",
dataType: "jsonp",
jsonp:"callback",//默认callback
/* 在一个 jsonp 请求中重写回调函数的名字。
这个值用来替代在 "callback=?" 这种 GET 或 POST 请求中 URL 参数里的 "callback" 部分
比如 {jsonp:'onJsonPLoad'} 会导致将 "onJsonPLoad=?" 传给服务器。*/
jsonpCallback: "leaf"
/* 自定义请求接口成功之后执行的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
类似:jQuery1111111111111_222222(["aa","bb","cc"])*/
})
}
// 请求接口成功之后执行的回调函数
function leaf(data) {
console.log(data);
// 执行代码
}
</script>
②后台如果发现传递过来的URL有callback参数,后台就知道这是一个JSONP请求;
③后台就会把返回的JSON数据用函数名a包裹起来,变成JS文件,这样JSON数据就变成了函数a里面的参数;
④前端动态引入这个JS文件,调用函数a就可以访问数据了;
(3)JSONP实现跨域的缺点?
- 服务器代码需要修改;
- 支持GET请求;
(如果指定请求方式为POST也是无效的,只能以GET方式请求); - 发送的不是XHR请求;
3、根据服务方和请求方来确定
(1)服务方:让服务器修改请求头支持跨域
思路:从a域名调用b域名的时候,b域名返回的数据中添加一些字段告诉浏览器:我允许a域名调用。如果浏览器通过校验,就不会报跨域问题。
(2)请求方:隐藏跨域,即设置反向代理
通过一个代理,然后从浏览器发出去的否是a域名的请求,在代理里面,把指定的url转到b域名里面,在浏览器看来,它就是同一个域名,就没有跨域问题。
即:访问同一个域名的两个不同url,最后会去了2两个不同的服务器。
常用的反向代理:Nginx代理