文章目录
一、同源策略
1.什么是同源
如果两个页面的协议,域名和端口都相同,则两个页面具有相同的源
类似于怎么知道两个人是不是老乡,相同省?相同市?
怎么知道两个页面来自于同一个地方(同一个源)?判断协议,域名和端口是否都相同。
端口如果没有指定:xxx,则默认是80
2.什么是同源策略
Same origin policy 是浏览器提供的一个安全功能
它限制了从同一个源加载的文档/脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
通俗理解:浏览器规定,A网站的Javascript,不允许和非同源的网站C之间进行资源的交互,例如:无法读取非同源网页的Cookie,LocalStorage和IndexedDB;无法接触非同源网页的DOM;无法向非同源地址发Ajax请求
二、跨域
1.什么是跨域
同源指的是两个URL的协议,域名,端口一致,反之,这三个中有任何一项/多项不一致,则是跨域。
出现跨域的根本原因:浏览器的同源策略不允许非同源的URL之间进行资源的交互
例如,网页http://www.test.com/index.html中调用Ajax请求接口:http://www.api.com/userlist中的数据,就会失败。
2.浏览器对跨域请求的拦截
注意:浏览器允许发起跨域请求,但是跨域请求回来的数据会被浏览器拦截,无法被页面获取到!
3.如何实现跨域数据请求
最主要的两种解决方案,分别是JSONP和CORS
JSONP:出现的早,兼容性好,是前端程序员为了解决跨域问题,被迫想出来的一种临时解决方案。缺点是只支持GET请求,不支持POST请求。
CORS:出现的较晚,它是W3C标准,属于跨域Ajax请求的根本解决方案,支持GET和POST请求。缺点是不兼容某些低版本的浏览器。
三、JSONP
JSON with Padding 是JSON的一种"使用模式",可用于解决主流浏览器的跨域数据访问的问题。
概念:浏览器端通过< script >标签的src属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做JSONP。
1.JSONP的实现原理
由于浏览器同源策略的限制,网页中无法通过Ajax请求非同源的接口数据。但是< script >标签不受浏览器同源策略的影响,可以通过src属性,请求非同源的js脚本。
因此,JSONP的实现原理,就是通过< script >标签的src属性,请求跨域数据接口,并且通过函数调用的形式,接收跨域接口响应回来的数据。
如果出现跨域问题,会报错:‘Access-Control-Allow-Orign’ header is present on the requested resource
(1)将函数的定义和调用分为两个script标签
<script>
var success=function(data){
console.log('拿到了data数据:')
console.log(data)
}
</script>
<script>
success({name:'zs',age:20})
</script>
(2)将函数的调用抽离为单独的JS文件
<script src="./js/1.js"></script>
(3)如果我们调用的是服务器的文件,里面有很多函数,那怎么能执行success这个函数呢?
通过callback指定回掉函数的名称
<script src="./js/1.js?callback=success"></script>
2.自己实现一个简单的JSONP
<script>
var success=function(data){
console.log('JSONP响应回来的数据是:')
console.log(data)
}
</script>
<script src="http://...:3006/api/jsonp?callback=success&name=zs&age=20"></script>
3.JSONP的缺点
只能支持GET数据请求,不支持POST请求
注意:JSONP和Ajax之间没有任何关系,不能把JSONP请求数据的方式叫做Ajax,因为JSONP没有用到XMLHttpRequest这个对象。
4.jQuery中的JSONP
jQuery提供的$.ajax()函数,除了可以发起真正的Ajax数据请求之外,还能够发起JSONP数据请求,例如
$.ajax({
url:'http://...:3006/api/jsonp?name=zs&age=20',
dataType:'jsonp',
success:function(res){
console.log(res)
}
})
默认情况下,使用jQuery发起JSONP请求,会自动携带一个callback-jQueryxxx的参数,jQueryxxx是随机生成的一个回掉函数名称。
5.自定义参数及回调函数名称
callback-jQueryxxx是随机生成的
自定义,需要如下两个参数来指定:jsonp(指定参数,默认是callback),jsonpCallback(指定回调函数名称,默认值是jQueryxxx格式)
$.ajax({
url:'http://...:3006/api/jsonp?name=zs&age=20',
dataType:'jsonp',
jsonp:'callback',
jsonpCallback:'abc',
success:function(res){
console.log(res)
}
})
6.jQuery中的JSONP的实现过程
jQuery中的JSONP也是通过< script >标签的src属性实现跨域数据访问的,只不过,jQuery采用的是动态创建和移除< script >标签的方式,来发起JSONP数据请求。
在发起JSONP请求的时候,动态向< header>中append一个< script>标签
在JSONP请求成功后,动态从< header>中移除刚才append进去的< script>标签
7.实现JSONP的接口
app.get('/api/jsonp',(req,res)=>{
// 1. 得到函数的名称
const funcName=req.query.callback
// 2. 定义要发送到客户端的数据对象
const data={name:'zs',age:22}
// 3. 拼接处一个函数调用
const scriptStr=`${funcName}(${JSON.stringify(data)})`
// 4. 把拼接好的字符串,响应给客户端
res.send(scriptStr)
})
四、CORS跨域资源共享
1.使用cors中间件解 决跨域问题
cors是Express的一个第三方中间件,通过安装和配置cors中间件,可以很方便地解决跨域问题
使用步骤分如下三步:
(1)运行npm install cors安装中间件
(2)使用const cors=require( ’ cors’ )导入中间件
(3)在路由之前调用app.use(cors())配置中间件
2.什么是CORS
Cross-Origin Resource Sharing,跨域资源共享,由一系列HTTP响应头组成,这些HTTP响应头决定浏览器是否阻止前端JS代码跨域获取资源
浏览器的同源安全策略默认会阻止网页"跨域"获取资源,但如果接口服务器配置了CORS相关HTTP响应头,就可以解除浏览器端的跨域访问限制。
3.CORS的注意事项
(1)CORS主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了CORS的接口
(2)CORS再浏览器中有兼容性。只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了CORS的服务端接口(例如:IE10+,Chrome4+,FireFox3.5+)
4.CORS响应头部___Access-Control-Allow-Origin
响应头部中可以携带一个Access-Control-Allow-Origin字段,其语法如下:
Access-Control-Allow-Origin: <origin> | *
其中,origin参数的值指定了允许访问该资源的外域URL
例如:下面的字段值将只允许来自http://xxx.cn的请求:
res.setHeader('Access-Control-Allow-Origin','http://xxx.cn')
如果指定了Access-Control-Allow-Origin字段的值为通配符*,表示允许来自任何域的请求,事例代码如下:
res.setHeader('Access-Control-Allow-Origin','*')
5.CORS响应头部___Access-Control-Allow-Headers
默认情况下,CORS仅支持客户端向服务器发送如下9个请求头:
Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type (值仅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)
客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过Access-Control-Allow-Headers对额外的请求头进行声明,否则这次请求会失败!
// 允许客户端额外向服务器发送Content-Type请求头和X-Custom-Header请求头
// 多个请求头之间用英文的,进行分隔
res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header')
5.CORS响应头部___Access-Control-Allow-Methods
默认情况下,CORS仅支持客户端发起GET,POST,HEAD请求
如果客户端希望通过PUT,DELETE等方式请求服务器资源,则需要在服务器端,通过Access-Control-Allow-Methods来指明实际请求所允许使用的HTTP方法。
事例代码如下:
// 只允许POST,GET,DELETE,HEAD请求方式
res.setHeader('Access-Control-Allow-Methods','POST,GET,DELETE,HEAD')
// 允许所有的HTTP请求方式
res.setHeader('Access-Control-Allow-Methods','*')
6.CORS请求的分类
客户端在请求CORS接口时,根据请求方式和请求头的不同,可以将CORS的请求分为两大类,分别是:
(1)简单请求
同时满足以下两大条件:
请求方式:GET,POST,HEAD三者之一;无定义头部字段
(2)简单请求
什么是预检请求?
在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的OPTION请求称为"预检请求"。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。
只要符合以下任何一个条件的请求,都需要进行预检请求:
请求方式是GET,POST,HEAD之外的请求Method类型;
请求头中包含自定义头部字段;
向服务器发送了application/json格式的 数据
(3)简单请求和简单请求之间的区别
简单请求的特点:客户端与服务器之间只会发生一次请求;
预检请求的特点:客户端与服务器之间会发生两次请求,OPTION预检请求成功后,才会发起真正的请求。