http请求发生两次(原来是options请求)

10,875 阅读3分钟

前言

Coding 应当是一生的事业,而不仅仅是 30 岁的青春🍚

今天分享一个需要前端去推进的优化小点,前端必看,后端也可以看看。

每篇文章都希望你能收获东西,这篇讲 OPTIONS 请求,看完希望你有这些收获:

  • OPTIONS 请求的作用以及由来
  • 哪些场景会出现 OPTIONS 请求
  • 如何处理每次请求都要 OPTIONS ,从而导致 2 次重复网络请求开销的问题

作用及由来

先简单回顾一下跨域请求,当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,此时会发起一个跨域 HTTP 请求。针对跨域,有多种解决方案,不展开说,不是今天的重点。

其中有一种方式叫做”跨域资源共享“(Cross-origin resource sharing),准确的说是一个W3C标准,可以克服同源策略的限制。

针对CORS请求,浏览器将其分成两个类型:简单请求和非简单请求,后面会展开说。

针对非简单请求,浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证等相关数据)。

OPTIONS 请求场景

首先我们需要区分一下简单请求跟非简单请求之间的差异。

只要满足下图(图片来自MDN)的条件,就是简单请求,反之为非简单请求。

针对非简单请求的CORS请求,会在正式通信之前,额外增加一次 HTTP 请求,称为"预检"请求(preflight),以获知服务器是否允许该实际请求,避免跨域请求对服务器产生未预期的影响。

如下图所示,第一次是 OPTIONS 预请求,第二次才是真实的请求。

很明显,如果我们不进行优化处理,只要是非简单请求,每一次都会出现先发一次 OPTIONS 预请求,然后才是真实请求,这样明显是不合理的。

解决方案

有两种方式可以来处理,我们分别来看看。

(1)全部用简单请求

这种方式不太行得通,毕竟现在大多数的场景都是非简单请求,例如我们需要自定义一些 header 等很多场景都会导致请求为非简单请求。

(2)Access-Control-Max-Age

Access-Control-Max-Age 这个响应头表示预请求的返回结果,即 Access-Control-Allow-Methods / Access-Control-Allow-Headers 可以被缓存多久,单位为秒。

例如下图,是怪怪用 koa 写的小例子,后端统一设置 Access-Control-Max-Age,就不会重复打 OPTIONS 请求了。

总结

细节决定成败,一个小的 OPTIONS 知识点分享给小伙伴。