为什么会发送OPTIONS请求

1

最近完成了一个番茄闹钟webApp:WJW-番茄土豆,小伙伴在帮忙测试bug的时候发现浏览器每次发送正式请求之前,都会发送一个OPTIONS请求:

微信图片_20200525140732.png

于是小伙伴本着考察我的目的对我发出了提问:为什么会发送OPTIONS请求?

2

2.1 什么是OPTIONS请求?

CORS MDN是这么描述的

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用OPTIONS方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

OPTIONS请求即预检请求,可用于检测服务器允许的http方法。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起OPTIONS请求,即CORS预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。

2.2 哪些请求会发送options请求?

这里就要说说请求的分类:简单请求和预检请求。
简单请求:满足以下几种情况(日常开发基本上只会注意前两种)

  1. 使用GET、POST、HEAD其中一种方法
  2. 只使用了如下的安全首部字段,不得人为设置其他首部字段
  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type 仅限以下三种:
    text/plain
    multipart/form-data
    application/x-www-form-urlencoded
  • HTML头部header field字段:DPR、Download、Save-Data、Viewport-Width、WIdth
  1. 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问
  2. 请求中没有使用 ReadableStream 对象

预检请求:满足以下几种情况

1.使用了PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH方法
2.人为设置了非规定内的其他首部字段,参考上面简单请求的安全字段集合,还要特别注意Content-Type的类型

  1. XMLHttpRequestUpload 对象注册了任何事件监听器
  2. 请求中使用了ReadableStream对象

请求附带身份凭证 >. cookies

发起请求时设置withCredentials 标志设置为true,从而向服务器发送cookie, 但是如果服务器端的响应中未携带Access-Control-Allow-Credentials: true,浏览器将不会把响应内容返回给请求的发送者。
对于附带身份凭证的请求,服务器不得设置Access-Control-Allow-Origin 的值为*, 必须是某个具体的域名。
注意,简单的GET请求不会触发预检,如果对此类带有身份凭证请求的响应中不包Access-Control-Allow-Credentials: true,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页

2.3 OPTIONS请求有什么?

  1. 预检请求头request header的关键字段:
    Access-Control-Request-Method:告诉服务器实际请求所使用的 HTTP 方法
    Access-Control-Request-Headers:告诉服务器实际请求所携带的自定义首部字段

服务器基于从预检请求头部获得的信息来判断,是否接受接下来的实际请求。

  1. 预检响应头response header的关键字段:
    Access-Control-Allow-Methods:返回了服务端允许的请求,包含GET/HEAD/PUT/PATCH/POST/DELETE
    Access-Control-Allow-Credentials:允许跨域携带cookie(跨域请求要携带cookie必须设置为true
    Access-Control-Allow-Origin:允许跨域请求的域名,这个可以在服务端配置一些信任的域名白名单
    Access-Control-Request-Headers:客户端请求所携带的自定义首部字段content-type

此次options请求返回了响应头的内容,但没有返回响应实体response body内容。

2.4 OPTIONS请求是否可以优化?

当然是可以的:

  1. OPTIONS预检请求的结果可以被缓存

·Access-Control-Max-Age这个响应首部表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-MethodsAccess-Control-Allow-Headers 提供的信息) 可以被缓存的最长时间,单位是秒。(MDN)
·如果值为 -1,则表示禁用缓存,每一次请求都需要提供预检请求,即用OPTIONS请求进行检测。

  1. 避免触发
    参考2.2 哪些请求会发送options请求? ,通过设置请求(比如三种Content-Type)来避免触发预检请求。

你可能感兴趣的:(为什么会发送OPTIONS请求)