概述
1、跨域的原因
跨域是是因为浏览器的同源策略限制,是浏览器的一种安全机制,服务端之间是不存在跨域的。
所谓同源指的是两个页面具有相同的协议、主机和端口,三者有任一不相同即会产生跨域。
2、跨域举例
3、跨域的解决办法
3.1 浏览器限制
既然跨域是浏览器的一种安全限制,那是否可以让浏览器不做跨域限制呢?答案是肯定的,我们设置浏览器禁止检查--disabled-web-security --user-data-dir,重新打开浏览器,会发现在浏览器顶部提示:
设置成功,跨域请求可被正常发送出去。
3.2、jsonp的实现方式
jsonp的实现原理为:虽然浏览器限制了页面直接向非同源的服务器发送ajax请求,但是并没有限制
页面向非同源的服务器请求JS脚本,就像我们可以使用标签请求任意域上图片一样。
当使用jsonp方式来实现跨域请求时,需要服务端进行配合。因为一般使用ajax请求从服务端返回的数据都是json对象,但是我们需要的是JS脚本,这就需要服务端将返回的数据形式变成JS脚本形式,所以jsonp是一种约定(实现方式将在下面进行讲解),是前后端为了实现跨域达成的一种协议。
当我们在本地请求慕课网上的地址时,控制台报错,提示跨域。(之所以请求慕课网的url,是因为慕课网支持jsonp,我们暂且理解为慕课网后台已经配合进行了改动)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="jquery-3.5.1.min.js"></script>
</head>
<body>
<a href="#" onclick="get1()">发生跨域请求</a>
<textarea id="text" style="width: 400px; height: 100px;"></textarea>
<script>
function get1() {
$.ajax({
url:"https://www.imooc.com/index/getstarlist",
type: "GET"
})
}
</script>
</body>
</html>
修改请求的方式,使用jsonp的方式发送跨域请求。在ajax请求中设置dataType="jsonp",
$.ajax({
url:"https://www.imooc.com/index/getstarlist",
type: "GET",
dataType:"jsonp"
})
这时候看到请求成功了。
服务端返回结果为:
细心观察发现,getstarlist请求后面自动跟上了callback参数,参数的值与服务端返回的函数名称相同
由此可以得出jsonp的实现原理为:当前端请求设置dataType="jsonp"时,浏览器会自动在url中添加callback="jqueryxxx"请求参数。对应服务器在接收到callback参数时,知道了这是一个jsonp请求,就会自动把返回的json对象转化为"jqueryxxx(json对象)"脚本的形式返回。
那为什么将dataType="jsonp"的形式,跨域请求就能成功呢?原因是因为当设置ajax请求的dataType="jsonp"时,实际上是在<html>的<head>中动态添加了一条<script>标签。
通过在开发者工具下的source下的jquery包中打断点,
刷新页面,可以看到dom元素中多了一条<script>标签,这条标签便是浏览器向服务端请求的JS脚本。
所以,jsonp向服务端发送的是script脚本,而普通的ajax请求发送的是xhr请求,这也是为什么使用jsonp能实现跨域的原因。
请求回来的js脚本(函数名称包裹的json对象)自动执行,默认success()函数作为回调函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="jquery-3.5.1.min.js"></script>
</head>
<body>
<a href="#" onclick="get1()">发生get1请求</a>
<textarea id="text" style="width: 400px; height: 100px;"></textarea>
<script>
function get1() {
$.ajax({
url:"https://www.imooc.com/index/getstarlist",
type: "GET",
dataType:"jsonp",
success:function(data){
var result = JSON.stringify(data); //json对象转成字符串
$("#text").val(result);
}
})
}
</script>
</body>
</html>
页面展示效果:
Jsonp的弊端:
虽然jsonp解决了跨域问题,但是存在以下几点弊端:
(1)jsonp需要服务端配合修改,如果调用的接口不是我们自己的服务器上,jsonp就无能无力了.
(2)jsonp只能发送get请求
(3)jsonp发送的时script请求,并不是xhr请求,因此xhr的很多优势都不能使用(例如:异步,事件等)
3.3 跨域资源共享cors解决跨域
在了解cors解决跨域之前,我们先来了解一下什么是简单请求和非简单请求。
工作中比较常见的简单请求:
- 请求方法为:HEAD、GET、POST中的一种。
- HTTP请求头中字段不超过:Accept、Accept-Language、Content-Language、Last-Event-ID
- Content-Type字段值为application/x-www-form-urlencoded
、
multipart/form-data、
text/plain中的一种。
满足以上条件的即为简单请求,否则即为非简单请求。
工作中常见的非简单请求:
- 请求方法为put、delete.
- 发送JSON格式的ajax请求。
- http中带自定义请求头。
对于简单请求:
浏览器发现是跨域请求,就会自动在请求头中加上Origin字段,代表请求来自哪个域(协议+主机名+端口号)。服务器在收到请求后,根据请求头中Origin字段值来判断是否允许跨域请求通过。具体实现方法是:在响应头Access-Control-Allow-Origin字段中设置指定的域名,表示允许这些域名的跨域请求。如果请求头中Origin字段的域名包含在这些域名中,则可以实现跨域请求(当然有时候还需要结合其他字段来判断),否则不通过。例如:
请求头信息:
GET /cors HTTP/1.1
Origin: http://localhost:8080/
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
Origin字段说明本次请求来自:http://localhost:8080/。
响应头信息:
Access-Control-Allow-Origin: http://localhost:8080/
Access-Control-Allow-Credentials: true
Content-Type: text/html; charset=utf-8
说明 http://localhost:8080/在服务器允许的范围内。
Access-Control-Allow-Credentials字段代表服务器允许cookie可以包含在请求中,一起发送给服务器,值为布尔类型。如果要把cookie一起发送到服务器,还需要在请求中打开withCredentials
属性。
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
注意:如果要发送cookie,Access-Control-Allow-Origin的值不能为“*”,只能是具体的域名。
非简单请求:
非简单请求在发送http请求时,会预先发送一次“预检”(OPTIONS)请求。预检请求会事先询问服务器,当前域名是否在服务器允许的范围内,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复后,浏览器才会真正发出http请求,否则就会报错。例如:
var url = 'http://localhost:8080/';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('Header-1', 'value');
xhr.send();
上述代码中,http发送了一条PUT请求,并且自定义请求头信息Header-1.
Access-Control-Allow-Origin: http://localhost:8080/
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Header-1
Content-Type: text/html; charset=utf-8
Access-Control-Max-Age: 3600
上述http响应中,说明服务器允许http://localhost:8080/请求数据,
Access-Control-Max-Age表示本次预检请求的有限期,单位为秒,在此期间内,不用发出另一条预检请求。
一旦服务器通过了“预检”请求,以后每次浏览器正常请求CORS请求,就跟简单请求一样。会有Origin字段,响应头里也会有对应的Access-Control-Allow-Origin字段。
CORS相比较JSONP的优势:
CORS支持所有类型的http请求,jsonp只支持get请求。JSONP的优势在于支持老式浏览器,以及向不支持CORS的网站请求数据。
3.4、nginx/apache/webpack中做相应配置
参考资料:
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://www.cnblogs.com/chiangchou/p/jsonp.html
https://www.imooc.com/learn/947
最后
以上就是痴情乌冬面为你收集整理的跨域的产生原因及解决方案的全部内容,希望文章能够帮你解决跨域的产生原因及解决方案所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复