如果 POST 不在预检选项响应的 Access-Control-Allow-Methods 值中,浏览器会阻止 POST 请求吗?

Do browsers block POST requests if POST isn’t in the Access-Control-Allow-Methods value of the preflight OPTIONS response?

我认为我对 CORS 非常了解,但我仍然对浏览器在预检请求方面的行为感到困惑。

假设浏览器发出此预检请求:

OPTIONS http://myserver.local:7000/api/order/4 HTTP/1.1
Host: myserver.local:7000
Connection: keep-alive
Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-my-custom-header
Origin: http://localhost:5000
Sec-Fetch-Mode: cors
Referer: http://localhost:5000/

和我的 API returns:

HTTP/1.1 204 No Content
Date: Wed, 09 Mar 2022 12:52:50 GMT
Server: Kestrel
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT,DELETE
Access-Control-Allow-Origin: http://localhost:5000
Vary: Origin

请注意,服务器允许在对预检请求的响应中使用方法 PUTDELETE,但不允许 POST,这是实际 CORS 请求的方法。

浏览器是否应该因为实际请求的方法与Access-Control-Allow-Methodsheader中列出的方法不匹配而阻止该请求?或者服务器以 [​​=19=] 状态代码响应浏览器接受预检然后发送实际请求就足够了吗?

我的假设是浏览器会比较 allow-methods 并在请求的方法不匹配时阻止请求...我是否遗漏了什么?

TL;DR

不,浏览器不要求服务器明确允许 POST 方法,因为后者作为 so-called CORS-safelisted method 获得免费通行证。


更多详情

规格说明

一如既往,答案在于 Fetch 标准 (section 4.8),它指定了 CORS 的工作方式:

  1. Let methods be the result of extracting header list values given Access-Control-Allow-Methods and response’s header list.

再往下:

  1. If request’s method is not in methods, request’s method is not a CORS-safelisted method, and request’s credentials mode is "include" or methods does not contain *, then return a network error.

(我的重点)

什么是CORS-safelisted方法?该术语在 section 2.2.1:

中定义

A CORS-safelisted method is a method that is GET, HEAD, or POST.

解读

如果 CORS 请求的方法是 GETHEADPOST 之一,浏览器不要求服务器在 Access-Control-Allow-Methods header CORS 预检成功。

实验

我在您的浏览器中发现 Jake Archibald's CORS playground useful for testing my (mis)understanding of CORS. Running this particular instance 可能会让您相信 POST 方法不需要明确允许 CORS 预检成功。