为什么ajax方法发出的post请求会生成options预请求?

分类:计算机 | 前端 | JavaScript | JQuery 1196
更新:2021-11-28 00:54:31
编辑

1 问题说明

最近在项目中使用ajax方法发送一个post请求时在后台通过HttpServletRequest的getMethod方法拦截到了http options请求,但是我并没有发送options预请求呀,这是怎么回事呢?

2 问题分析

options预请求会在什么情况下出现:

1、跨域调用,例如:调试时候很多情况都是在跨域的情况下进行调试。

2、自定义请求头部header字段:比如业务需求,传一个字段,方便后端获取,不需要每个接口都传。

3、请求头的content-type参数是"application/x-www-form-urlencoded"、"multipart/form-data"、"text/plain"之外的其它格式,例如:application/json。

以上三种情况出现就会出现options请求了,说白了就是为了服务器安全,例如:同源策略引发这个规则;options通常是浏览器自动发起的,目的就是去服务器检查一下接下来要用到的方法(GET、POST、PUT、DELETE)在服务器上是否支持。

3 相关说明

3.1 什么是预请求?

预请求就是复杂请求(可能对服务器数据产生副作用的http请求方法,如put,delete都会对服务器数据进行修改,所以要先询问服务器)。

跨域请求中,浏览器自发的发起预请求,浏览器会查询到两次请求,第一次的请求参数是options,以检测实际请求是否可以被浏览器接受。

3.2 为什么需要预请求?

w3c规范要求,对复杂请求,浏览器必须先使用options发起一个预检请求,从而获知服务器是否允许该跨域请求,服务器确认以后才能发起实际的HTTP请求,否则停止第二次正式请求。

那为什么我们不常见options请求呢?因为大部分我们使用的是get,post请求,他们属于简单请求,而简单请求不会触发options请求。

3.3 为什么需要设置成contentType:"application/json"?

ajax发送复杂的json数据结构, 处理方式困难, 服务器端难以解析, 所以就有了application/json这种类型(数据格式的声明)服务端好解析并且比较统一,如果你请求中没有设置成json格式的,有的服务端收到后也会改成json格式的,但是如果请求中就改成了json格式就会发生options预请求。

如果设置了contentType:"application/json":

  • ajax的data只能是json格式的字符串,发送的json对象必须使用json.stringify进行序列化字符串才能匹配。
  • Spring需要使用@RequestBody来注解。 例如:
    $.ajax({
      url: actionurl,
      type: "POST",
      datType: "JSON",
      contentType: "application/json"
      data: "{'id': " + nodeId +"}",
      async: false,
      success: function () {}
    });
    

如果没有设置contentType:"application/json"的话,那么ajax的data可以是对象,例如:

$.ajax({
    url: actionurl,
    type: "POST",
    datType: "JSON",
    data: { id: nodeId },
    async: false,
    success: function () {}
});

3.4 options的作用

OPTIONS请求方法的主要用途有两个:

  • 获取服务器支持的HTTP请求方法;也是黑客经常使用的方法。
  • 用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个options请求头,用以判断实际发送的请求是否安全。

参考资料

HTTP 之 options预请求

Http协议:什么情况下发生了options请求?