为什么浏览器允许 xorigin POST 但不允许 PUT?

Why does the browser allow xorigin POST but not PUT?

考虑使用 XMLHttpRequest.

的非常简单的示例

以下帖子正确(您可以在网络选项卡中看到它,或者将浏览器定向到 http://requestb.in/yckncpyc),尽管它会向控制台打印警告

XMLHttpRequest cannot load http://requestb.in/yckncpyc. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

const method = "POST"
const req = new XMLHttpRequest() 
req.open(method, 'http://requestb.in/yckncpyc')
req.send("foobar")
console.log("sent")
req.addEventListener('load', function() { console.log(req.status, req.response) })

当然可以。我明白了。我不明白的是,为什么仅将用于 PUT 的动词更改为完全不同的结果。发送的请求是 OPTIONS 预检请求并打印

XMLHttpRequest cannot load http://requestb.in/yckncpyc. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

const method = "PUT"
const req = new XMLHttpRequest() 
req.open(method, 'http://requestb.in/yckncpyc')
req.send("foobar")
console.log("sent")
req.addEventListener('load', function() { console.log(req.status, req.response) })

为什么浏览器* 以不同方式对待这些?这似乎是为了安全而做的事情,但实际上没有任何意义,因为攻击者总是可以使用 POST 而不是 PUT。

那么这里的逻辑是什么?

GETHEADPOST 请求(有一些其他限制)可以 cross-origin 进行,无需额外的通信。无法检查响应,但允许请求。

其他任何事情都需要 preflight 请求来检查来自目标站点的 headers 以查看请求是否被允许。

这样设置的原因是 GETHEADPOST 在历史上被浏览器允许作为 HTML 语义的自然组成部分。脚本和 CSS 的标签以及图像执行 GET 请求,表单执行 POST。因此,当引入 CORS 内容时,允许这些内容的前提是站点不再像 XHR 世界中那样容易受到简单请求的攻击,然后它们处于更简单的 non-XHR 世界中。

如此简单的请求是允许的,浏览器查看响应headers来决定是否允许cross-origin页面中的请求代码看到响应内容。对于其他请求,浏览器首先发送一个OPTIONS请求来检查CORS响应headers。只有当看起来没问题时(也就是说,如果响应 headers 包含适当的 "yes that's OK" headers)才会允许 XHR 继续。