AJAX请求中出现OPTIONS请求
背景
有一个前后端分离的VUE项目来发送ajax
请求, 查看Nginx
日志或使用Chrome Dev Tools
查看请求发送情况时, 会看到每次调后台API的请求之前, 都会发送一个OPTIONS请求, 无论API要求请求的方法是GET或POST.
为什么会发送这个OPTIONS请求? 困扰了项目组的前端同学和后端同学很久,今天正好听他们说起这个问题,就研究了一下原理。
过程
首先, 在js代码里是没写要发送OPTIONS请求的, 后台API要的请求方法不是GET就是POST, 也只发送过这两种类型的请求.
那么, 我就以为是前台调用方式的问题, 于是去看了看代码. 发现并没有什么很特殊的地方。然后直接看ajax.js
文件. 结果, 发现一切正常, 并没有这种逻辑: 发送GET/POST请求之前, 先发送一个OPTIONS请求.
看来就不是前端同学写法的问题,也不是ajax的问题,仔细对比了一下之前的代码,发现唯一的区别就是ajax中用到了自定义的header头。
解惑
众所周知, ajax请求是由XMLHttpRequest
对象实现的(部分低版本ID浏览器不是), 而XMLHttpRequest
会遵守同源策略(same-origin policy). 也即脚本只能访问相同协议/相同主机名/相同端口的资源, 如果要突破这个限制, 那就是所谓的跨域, 此时需要遵守CORS(Cross-Origin Resource Sharing)机制。
那么, 允许跨域, 不就是服务端(例如Nginx或者后端代码)设置Access-Control-Allow-Origin: *
就可以了吗?
普通的请求确实是这样子的, 除此之外, 还一种叫请求叫Preflighted Request(带预检的跨域请求)
Preflighted Request在发送真正的请求前, 会先发送一个方法为OPTIONS的预请求(Preflighted Request), 用于试探服务端是否能接受真正的请求.
如果options获得的回应是拒绝性质的,比如404\403\500等http状态,就会停止post、get等请求的发出。
那么, 什么情况下请求会变成Preflighted Request呢? 翻看了MDN的文档发现如下:(文档地址:https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#The_HTTP_request_headers)
- 请求方法不是GET/HEAD/POST
- POST请求的
Content-Type
并非application/x-www-form-urlencoded
,multipart/form-data
, 或text/plain
- 请求设置了自定义的
header
字段
举个例子, 如果POST请求要传输的数据为 XML文档, Content-Type
为application/xml
或text/xml
, 则发送这个请求前会发送一个预请求,或者自定义的header字段也是一样的道理。
有了上面的知识点, 再去看项目中ajax调用
可以看出, 跨域请求中设置了自定义的header
字段, 所以该请求是preflighted request
, 则请求前一定会发送一个OPTIONS作为预请求.
所以说, 在项目中ajax对后台API的调用, OPTIONS请求是没办法去掉的, 除非后台接口不再需要在请求header
中设置openId
但是由于该项目中用户信息是采用的JWT的方式,所以只好作罢。
但是由于该项目在后台中自定义了请求频率限制的拦截器,例如限制同一个客户端一秒内对某一个接口只能访问1次。如果超过限制,则第二次会返回状态码500,不予处理。如果每次请求前都带着一次OPTIONS请求,则该拦截器无法正常实现功能,反正会导致大批接口调用失败的情况。
鉴于上述分析,既然前端发起请求时OPTIONS请求没有办法去除,那么是否可以考虑从后台拦截器进行改造。
改造后的代码如下:
如果拦截到的请求不是项目中常规的GET或者POST请求,则该拦截器直接放行。至此,问题完美解决。希望可以帮到有类似问题的小伙伴~