POST 为什么会发送两次请求?
-
在发送 POST 请求时,如果该请求需要携带自定义的请求头部信息,也会触发预检请求。这是因为简单请求(无自定义请求头)不会触发预检请求,只有复杂请求(有自定义请求头)才需要先进行预检请求,以确保服务器允许该请求携带自定义的请求头部信息。
-
因此,当发送带有自定义请求头的 POST 请求时,浏览器会先发送一个 OPTIONS 请求进行预检,如果服务器允许该请求,则浏览器会再次发送实际的 POST 请求。这就是为什么有时候会看到 POST 请求被发送了两次的情况。
-
另外,可能会发送两次请求的原因是浏览器缓存问题。有些浏览器会在发送 POST 请求时先发送一次 OPTIONS 预检请求,如果之前已经进行过预检请求并得到服务器的允许,浏览器会将预检结果缓存起来,下次再发送 POST 请求时就不会再发送预检请求了。但如果缓存过期或被清除,浏览器会重新发送预检请求。因此,有时候我们看到的两次请求其实是一次实际请求和一次预检请求。
不会触发 CORS 预检请求。这样的请求为 简单请求,。若请求满足所有下述条件,则该请求可视为 简单请求:
HTTP 方法限制:只能使用 GET、HEAD、POST 这三种 HTTP 方法之一。如果请求使用了其他 HTTP 方法,就不再被视为简单请求。
自定义标头限制:请求的 HTTP 标头只能是以下几种常见的标头:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(仅限于 application/x-www-form-urlencoded、multipart/form-data、text/plain)。HTML 头部 header field 字段:DPR、Download、Save-Data、Viewport-Width、WIdth。如果请求使用了其他标头,同样不再被视为简单请求。
请求中没有使用 ReadableStream 对象。
不使用自定义请求标头:请求不能包含用户自定义的标头。
请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问
预检请求
非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为 预检请求。
需预检的请求要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。预检请求 的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。