最近开发过程中,为了避免跨域,于是在服务端添加了Access-Control-Allow-Origin
,前端出现一个小异常,每次请求次数都是2次,第一次请求的methods
为options
,第二次才是正式的请求。每个接口请求2次很浪费资源,百度了下,这个请求叫做预请求,现在就来学习下。
一、什么是预请求?
跨域请求资源时浏览器为确认请求来源的安全性,会在正式的请求之前做一次预校验请求,待服务器允许之后才能发送正式的请求,这个预校验请求就是options
请求。
并不是每次跨域资源请求都会发送options
请求,当跨域请求为简单请求的时就不会发送预校验请求,当跨域请求为复杂请求时才会发送预校验请求。
什么是简单请求?
- 请求方式只能是:
GET
、POST
、HEAD
。 -
HTTP
请求头限制这几种字段:Accept
、Accept-Language
、Content-Language
、Content-Type
、Last-Event-ID
。 -
Content-type
只能取:application/x-www-form-urlencoded
、multipart/form-data
、text/plain
。
如果不满足以上条件的就是非简单请求。
二、如何避免预请求?
预请求是浏览器的一种安全策略,但是它的存在给会占用浏览器的资源,影响页面的性能,所以要尽可能的减少options
请求。而方法也很简单,使用简单请求即可:
注意以下几点:
- 而在日常开发中,比如
Axios
里面默认的content-type
为application/json
,这就需要将content-type
修改成application/x-www-form-urlencoded
即可。 - 如果是
post
请求的话,需要对参数做个处理,需要引用qs
库,将qs.stringify
将参数序列化进行传参。
如果以上没问题,但是还是有预请求的话,需要查看header
里是否设置了其他参数,因为在项目开发中经常会将token
放到header
里进行传参,这种场景需要后端使用Access-Control-Max-Age
。
Access-Control-Max-Age
的作用
用来指定本次预检请求的有效期,单位为秒,这样只有在第一次请求的时候会有options
,之后浏览器会从缓存里读取响应,也就不会再发送options
请求。
Access-Control-Max-Age
为0
表示每次异步请求都发起预检请求,也就是说,发送两次请求。
Access-Control-Max-Age
为1800
表示隔30分钟才发起预检请求。