Drcus | 王亚振

Drcus | 王亚振

随便写,记录点东西

记录一次跨域问题

发布于:  

前提 服务端的 Response Headers 已经添加了

Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *

直接用fetch 访问是可以拿到数据的 接口正常。

目前问题:

  1. 请求之前会先发起一个 OPTIONS 请求 Status Code: 200
  2. 发起正常请求 但是不成功。 控制台显示 Provisional headers are shown

查阅相关资料后疑惑解决。

  1. 为什么会有 OPTIONS 请求

MDN 有一段话

HTTP 的 OPTIONS 方法 用于获取目的资源所支持的通信选项。客户端可以对特定的 URL 使用 OPTIONS 方法,也可以对整站(通过将 URL 设置为“*”)使用该方法。

也就是说,可以用 options 请求去嗅探某个请求在对应的服务器中都支持哪种请求方法。

我们一般不会主动发起这个请求,但是往往你可以看到浏览器中相同的请求发起了 2 次,这是因为在跨域的情况下,在浏览器发起"复杂请求"时主动发起的。跨域共享标准规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。

简单请求和复杂请求

某些请求不会触发 CORS 预检请求,这样的请求一般称为"简单请求",而会触发预检的请求则称为"复杂请求"。

简单请求

  • 请求方法为GET、HEAD、POST时发的请求
  • 人为设置了规范集合之内的首部字段,如Accept/Accept-Language/Content-Language/Content-Type/DPR/Downlink/Save-Data/Viewport-Width/Width
  • Content-Type 的值仅限于下列三者之一, 即 application/x-www-form-urlencoded、multipart/form-data、text/plain
  • 请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器
  • 请求中没有使用 ReadableStream 对象

复杂请求

  • 使用了下面任一 HTTP 方法,PUT/DELETE/CONNECT/OPTIONS/TRACE/PATCH
  • 人为设置了以下集合之外首部字段,即简单请求外的字段
  • Content-Type 的值不属于下列之一,即application/x-www-form-urlencoded、multipart/form-data、text/plain

OPTIONS 请求优化

当我们发起跨域请求时,如果是简单请求,那么我们只会发出一次请求,但是如果是复杂请求则先发出 options 请求,用于确认目标资源是否支持跨域,然后浏览器会根据服务端响应的 header 自动处理剩余的请求,如果响应支持跨域,则继续发出正常请求,如果不支持,则在控制台显示错误。

由此可见,当触发预检时,跨域请求便会发送 2 次请求,既增加了请求数,也延迟了请求真正发起的时间,严重影响性能。

所以,我们可以优化 Options 请求,主要有 2 种方法。

  1. 转为简单请求
  2. 对 options 请求进行缓存

最好采用方案一, 减少请求 降低服务器负载。

~^_^~ 一片小花园 ?

赏赐