浏览器发出多余的 OPTIONS
请求,通常与跨域请求(CORS)和某些特定的请求条件有关。以下是一些常见导致浏览器发出“额外” OPTIONS
请求的情况:
🧠 1. 跨域请求 + 非简单请求
当你从网页发起跨域请求(即请求的域、端口或协议与页面不同),并且该请求不是“简单请求”时,浏览器会先发出 预检请求(preflight),即 OPTIONS
请求。
非简单请求的特征:
-
使用的方法不是
GET
、HEAD
、POST
; -
或者
POST
请求中Content-Type
不属于下列之一:-
application/x-www-form-urlencoded
-
multipart/form-data
-
text/plain
-
-
或者设置了自定义的请求头(如
Authorization
,X-Token
等)。
📌 示例:
fetch("https://api.example.com/data", {
method: "PUT", // 非简单方法
headers: {
"Content-Type": "application/json" // 非简单 Content-Type
},
body: JSON.stringify({ key: "value" })
});
这会触发一个 OPTIONS
请求作为预检。
🧠 2. 自定义请求头
即便是 GET
或 POST
,只要你添加了非标准头部字段,也会触发 OPTIONS
请求。
例如添加了 Authorization
:
fetch("/api", {
headers: {
"Authorization": "Bearer token"
}
});
🧠 3. 不同的协议、端口或子域
即便你访问的是同一个主域名,但只要协议或端口不同,也会被视为跨域。
示例:
-
https://example.com
与http://example.com
-
https://example.com
与https://api.example.com
-
https://example.com
与https://example.com:8443
🧠 4. 某些浏览器或框架行为
一些 JavaScript 库或浏览器插件可能自动添加 header,导致触发预检。例如:
-
Axios 默认加了
X-Requested-With
; -
某些安全策略插件;
-
DevTools 中模拟移动设备。
🧠 5. 缓存未命中
如果服务器未设置 Access-Control-Max-Age
或时间太短,则每次跨域请求都必须重新预检,从而产生重复的 OPTIONS
。
✅ 减少 OPTIONS 请求的方法
-
尽量使用“简单请求”:如
GET
、POST
(使用application/x-www-form-urlencoded
); -
避免自定义请求头(或将其放在 body 中);
-
使用同源策略;
-
设置合理的
Access-Control-Max-Age
响应头缓存预检结果。
这些 OPTIONS
请求最主要的意义,是出于 安全性考虑,尤其是在 跨域资源共享(CORS) 机制下,用于浏览器与服务器之间的一种 “探测”或“预检”机制。
✅ OPTIONS 请求的核心意义
1. 预检请求(Preflight)——浏览器在正式请求前的安全确认
当网页 JavaScript 代码要发起一个“非简单”的跨域请求时,浏览器为了保护用户安全,不会立刻发送这个请求,而是先自动发一个 OPTIONS
请求到服务器,来询问:
“我要用这个方法(如 PUT),并带这些头(如 Authorization),你允许我这么做吗?”
服务器的责任:
-
通过返回的
Access-Control-Allow-*
头告诉浏览器:-
是否允许这个源(Origin)访问;
-
允许的方法(如
GET
,POST
,PUT
); -
允许的请求头字段;
-
是否允许携带 cookie;
-
预检缓存时长(
Access-Control-Max-Age
);
-
2. 避免跨站攻击(CSRF、XSS)对敏感接口的滥用
举例来说,假如没有预检机制:
-
一个恶意网页就可以随意给用户的银行后台接口发
PUT /transfer
请求,伪造转账; -
而浏览器默认会带上用户当前的 Cookie/session,这会导致严重的账户劫持问题。
📌 通过 OPTIONS
预检,服务器可以拒绝这些未经授权的跨源请求,从而保护用户。
3. 通用性用途(不局限于 CORS)
OPTIONS
方法本身是 HTTP 协议的一部分,含义是:
“告诉我这个 URL 支持哪些 HTTP 方法”
在一些 RESTful API 或服务器调试场景下,可以手动发送 OPTIONS
请求来获知资源支持的操作:
OPTIONS /api/user HTTP/1.1
Host: example.com
服务器返回:
Allow: GET, POST, PUT, DELETE
🧾 总结:OPTIONS 请求 ≠ 多余请求
情况 | 是否必须 | 目的 |
---|---|---|
跨域 + 非简单请求 | ✅ 是 | 浏览器的安全机制,用于询问服务端是否允许 |
自定义 Header | ✅ 是 | 浏览器无法预知服务器是否支持这些 Header |
RESTful 手动调用 | ❌ 可选 | 用户主动探测 API 能力 |