前端进阶:详解跨域请求中神秘的 OPTIONS 预检请求
为什么浏览器有时候会发送一个 options 请求?有时候又没有?明明我们的代码中根本就没写options请求,它到底是在什么情况下才会出现?
先说一个结论:OPTIONS 请求是「浏览器专用」、且「自动发送」的。
一、什么时候浏览器会发 OPTIONS 请求?
很多人都误以为:只有 POST、PUT 请求才会发送 OPTIONS,GET 请求不会发送。
其实不是,只要满足了下面两个条件,就会触发 OPTIONS:
- 跨域
- 非简单请求
也是就:非简单请求跨域访问的时候,浏览器就会自动发送 OPTIONS 请求。
跨域我们都知道,就不多介绍了,那什么是非简单请求呢?
1. GET、POST、HEAD 之外的请求方法
只要不是这 3 个请求方法,都是非简单请求。
2. 自定义 Header
只要存在自定义的 Header,就是非简单请求。
headers: {
'cityId': 'beijing',
}3. 非简单 Header
简单请求的 Header 只允许以下这些信息:
Accept
Accept-Language
Content-Language
Content-Type(只能是下面 3 种值)
text/plain
application/x-www-form-urlencoded
multipart/form-data只要包含除此之外的信息,都是非简单请求。
TIP
比如:我们经常使用的application/json,就是非简单请求。
4. 携带凭证
fetch(url, {
credentials: 'include',
})二、浏览器为什么要发送 OPTIONS 请求?
OPTIONS 请求也就是我们常说的预检请求(Preflight),

浏览器在发送跨域请求之前,会先询问服务器:
我等下要发送这个方法、这些 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,通常都会在业务代码之前进行处理,来告诉浏览器我能接受哪些跨域的请求。
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 其实是浏览器在帮你做安全确认,不要搞错了哦。