跳转到内容

前端进阶:详解跨域请求中神秘的 OPTIONS 预检请求

为什么浏览器有时候会发送一个 options 请求?有时候又没有?明明我们的代码中根本就没写options请求,它到底是在什么情况下才会出现?

先说一个结论:OPTIONS 请求是「浏览器专用」、且「自动发送」的

一、什么时候浏览器会发 OPTIONS 请求?

很多人都误以为:只有 POST、PUT 请求才会发送 OPTIONS,GET 请求不会发送。

其实不是,只要满足了下面两个条件,就会触发 OPTIONS:

  • 跨域
  • 非简单请求

也是就:非简单请求跨域访问的时候,浏览器就会自动发送 OPTIONS 请求

跨域我们都知道,就不多介绍了,那什么是非简单请求呢?

1. GET、POST、HEAD 之外的请求方法

只要不是这 3 个请求方法,都是非简单请求。

2. 自定义 Header

只要存在自定义的 Header,就是非简单请求。

ts
headers: {
  'cityId': 'beijing',
}

3. 非简单 Header

简单请求的 Header 只允许以下这些信息:

txt
Accept
Accept-Language
Content-Language
Content-Type(只能是下面 3 种值)

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

只要包含除此之外的信息,都是非简单请求。

TIP

比如:我们经常使用的application/json,就是非简单请求。

4. 携带凭证

ts
fetch(url, {
  credentials: 'include',
})

二、浏览器为什么要发送 OPTIONS 请求?

OPTIONS 请求也就是我们常说的预检请求(Preflight)

20251231094305_image.png

浏览器在发送跨域请求之前,会先询问服务器:

我等下要发送这个方法、这些 HEADER,你是否允许?

这个询问的请求就是 OPTIONS 请求。

如果服务器没有允许,浏览器就会直接中断这个跨域请求。

浏览器为什么要这么做?其实还是为了安全。

试想一下,如果一个恶意的网站,拿到了用户的登录态后,随意地做一些事情是非常危险的。

有了预检请求,浏览器会在做这些操作之前,先询问浏览器:

  • 这个 origin (请求来源站点)是否允许?
    http
    Access-Control-Allow-Origin: https://example.com
  • 这个请求方法是否允许?
    http
    Access-Control-Allow-Methods: POST, PUT, DELETE
  • 这些 header 是否允许?
    http
    Access-Control-Allow-Headers: Content-Type, Authorization
  • 是否允许携带凭证?
    http
    Access-Control-Allow-Credentials: true

如果服务器拒绝,浏览器就不会发送正式的请求操作,从而保证了安全性。

三、服务端如何处理?

现在我们知道:OPTIONS 请求是浏览器行为,它是在跨域、非简单请求发起之前,先向服务器进行确认

所以,服务端要处理 OPTONS,通常都会在业务代码之前进行处理,来告诉浏览器我能接受哪些跨域的请求。

ts
if (request.method === 'OPTIONS') {
  return new Response(null, {
    status: 204,
    // 设置允许的 origin、method、Header
    headers: {
      'Access-Control-Allow-Origin': 'http://localhost:3000',
      'Access-Control-Allow-Methods': 'GET,POST,OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    },
  })
}

// 正常业务代码

浏览器在接收到 OPTIONS 请求的响应头信息后,就会判断服务器是否允许发送接下来的请求

如果服务器不处理 OPTIONS 会怎样?

对浏览器来说,只要没得到服务器明确的答复,就不会发送后面正式的请求。所以,服务器必须同时在 OPTIONS 和原本请求上都要加上对应的跨域 Header 信息。

为什么 OPTIONS 返回的状态码是 204?

因为浏览器只关心 OPTIONS 返回的 Header 信息,不关心其内容。204 表示 No Content 正好符合此语义(非强制)。

最后总结

跨域、非简单请求发起之前,浏览器会自动发送 OPTIONS 请求,先向服务器确认是否允许。

所以,OPTIONS 其实是浏览器在帮你做安全确认,不要搞错了哦。