预检请求

什么是预检请求?

对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。 CORS请求失败会产生错误,但是为了安全,在JavaScript代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

简单请求与预检请求 - 图1

什么情况下会有预检请求

请求会对服务器有影响的会先法预检请求

当请求满足下述任一条件时,即应首先发送预检请求:

  • 使用了下面任一 HTTP 方法:
  • 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (需要注意额外的限制)
    • [DPR](http://httpwg.org/http-extensions/client-hints.html#dpr)
    • [Downlink](http://httpwg.org/http-extensions/client-hints.html#downlink)
    • [Save-Data](http://httpwg.org/http-extensions/client-hints.html#save-data)
    • [Viewport-Width](http://httpwg.org/http-extensions/client-hints.html#viewport-width)
    • [Width](http://httpwg.org/http-extensions/client-hints.html#width)
  • Content-Type的值不属于下列之一:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • 请求中的XMLHttpRequestUpload 对象注册了任意多个事件监听器。
  • 请求中使用了ReadableStream对象。

简单请求

什么是简单请求?

某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:

什么请求是简单请求

按照预检请求的理解,简单请求就是对服务器无副作用的请求。

  • 使用下列方法之一:
  • Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。该集合为:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (需要注意额外的限制)
    • [DPR](http://httpwg.org/http-extensions/client-hints.html#dpr)
    • [Downlink](http://httpwg.org/http-extensions/client-hints.html#downlink)
    • [Save-Data](http://httpwg.org/http-extensions/client-hints.html#save-data)
    • [Viewport-Width](http://httpwg.org/http-extensions/client-hints.html#viewport-width)
    • [Width](http://httpwg.org/http-extensions/client-hints.html#width)
  • Content-Type的值仅限于下列三者之一:
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  • 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
  • 请求中没有使用 ReadableStream 对象。

POST为什么分简单和不简单

**

搭配某些 MIME 类型的 POST 请求,需要发送预检请求,怎么理解? 为什么POST请求划分到简单请求里?

为什么content-type为下面三种的却被视为简单请求,工作中碰到的post请求很多都会采用下面的格式,且会修改数据库内容,其不会存在安全风险吗?

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

如果我们现在重新设计整个HTTP协议,我们可以要求浏览器在发送任何数据到另外一个域的服务器之前,都必须先发送preflight request。但是大部分现存网站并未针对preflight request做出实现,所以这意味着现有的互联网中,如果一个域的表单向另一个域提交的时候会跨域失败,直到目标网站更新处理perflight request为止。

所以在我们制定这一新的标准的时候,应当考虑到目前互联网已经存在这样的请求,他们虽然看起来可能不安全,但为了向下兼容,我们不能强制对这些请求做preflight request。既然不能强制做preflight request验证,那发这个东西就没有什么意义了。

可能是为了向下兼容表单提交吧,表单提交出现比同源策略要早。


参考mdn
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
知乎
https://www.zhihu.com/question/268998684