<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>之前有一个项目使用<code>Zepto</code>来发送<code>ajax</code>请求, 查看<code>Nginx</code>日志或使用<code>Chrome Dev Tools</code>查看请求发送情况时, 会看到每次调后台API的请求之前, 都会发送一个OPTIONS请求, 无论API要求请求的方法是GET或POST. </p>
为什么会发送这个OPTIONS请求? 可以去掉吗?
过程
首先, 我在js代码里是没写要发送OPTIONS请求的, 后台API要的请求方法不是GET就是POST, 我只发送过这两种类型的请求.
那么, 我就以为是Zepto
搞的鬼, 于是去看它的源码. Zepto
的源码模块化做得很好, 直接看里面的ajax.js
文件就好了. 结果, 我发现一切正常啊, 并没有这种逻辑: 发送GET/POST请求之前, 先发送一个OPTIONS请求.
不是Zepto
的问题, 那我只好使用搜索大法了.
stackoverflow.com一搜, 找到了一个相似的问题, 再根据回答找到MDN的文档, 这才知道前因后果.
解惑
众所周知, ajax请求是由XMLHttpRequest
对象实现的(IE10以下的浏览器不是), 而XMLHttpRequest
会遵守同源策略(same-origin policy). 也即脚本只能访问相同协议/相同主机名/相同端口的资源, 如果要突破这个限制, 那就是所谓的跨域, 此时需要遵守CORS(Cross-Origin Resource Sharing)机制
那么, 允许跨域, 不就是服务端(例如Nginx)设置Access-Control-Allow-Origin: *
就可以了吗? 普通的请求才是这样子的, 除此之外, 还一种叫请求叫preflighted request
preflighted request
在发送真正的请求前, 会先发送一个方法为OPTIONS的预请求(preflight request
), 用于试探服务端是否能接受真正的请求.
那么, 什么情况下请求会变成preflighted request
呢? 文档中指出的是:
- 请求方法不是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
, 则发送这个请求前会发送一个预请求
有了上面的知识点, 再去看项目中ajax调用
|
|
可以看出, 跨域请求中设置了自定义的header
字段, 所以该请求是preflighted request
, 则请求前一定会发送一个OPTIONS作为预请求.
所以说, 在项目中ajax对后台API的调用, OPTIONS请求是不可以去掉的, 除非后台接口不再需要在请求header
中设置openId
哈哈, 明白了这个道理就好办啦, 后台同学再让我把这个请求去掉, 我就说”臣妾做不到啊”
参考资料
- http://stackoverflow.com/questions/1256593/why-am-i-getting-an-options-request-instead-of-a-get-request
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
</div>