fetch触发OPTIONS预检当使用PUT/DELETE等非常规方法、含自定义请求头或非标准Content-Type时;前端可降级为简单请求规避,但需后端配合,且credentials需显式设为include并配对应响应头。

JavaScript 无法绕过浏览器的同源策略直接请求不同源的后端 API,CORS 不是前端能“解决”的问题,而是必须由后端配置响应头;但前端可以主动规避预检(preflight)或适配其行为。
为什么 fetch 会触发 OPTIONS 预检请求
当 fetch 发出的请求满足以下任一条件时,浏览器会在发实际请求前自动发送一个 OPTIONS 请求(即预检):
- 使用了除
GET、HEAD、POST之外的 HTTP 方法(如PUT、DELETE) - 设置了自定义请求头(如
Authorization、X-Request-ID) -
Content-Type不是以下三种之一:text/plain、multipart/form-data、application/x-www-form-urlencoded
预检失败(如后端未返回 Access-Control-Allow-Origin 等头)会导致整个请求被浏览器拦截,控制台报错 Failed to fetch 或 No 'Access-Control-Allow-Origin' header。
如何让前端不触发预检(简单场景适用)
如果后端暂时无法改 CORS 配置,可尝试让请求“降级”为简单请求:
立即学习“Java免费学习笔记(深入)”;
- 用
POST代替PUT/DELETE,并在 body 中传{_method: "PUT"}(需后端配合解析) - 避免设置
Authorization头,改用 query 参数或 cookie(前提是后端支持且 cookie 已开启withCredentials) - 传 JSON 时不要手动设
Content-Type: application/json,改用JSON.stringify()+ 默认text/plain(但后端可能无法解析,慎用) - 若必须传 JSON 且要免预检,唯一合规方式是后端把
Content-Type: application/json加入Access-Control-Allow-Headers
fetch 中正确处理 withCredentials 和 credentials
当需要携带 Cookie 或认证信息时,credentials 选项不能省略或设为 "omit":
fetch('https://api.example.com/data', {
method: 'GET',
credentials: 'include' // 必须显式写,不能依赖默认值
})
同时后端响应头必须包含:
-
Access-Control-Allow-Origin: https://your-frontend-domain.com(不能为*) Access-Control-Allow-Credentials: true
漏掉任意一项,浏览器都会拒绝响应。注意:本地开发时 http://localhost:3000 和 http://127.0.0.1:3000 被视为不同源,也需分别配置。
调试预检失败最有效的三步
遇到 CORS 报错,别急着改前端代码:
- 打开浏览器 DevTools → Network → 找到那个
OPTIONS请求 → 看 Response Headers 是否含Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers - 检查该
OPTIONS响应状态码是否为200(不是404或405) - 确认后端是否对
OPTIONS请求做了特殊拦截(如某些框架默认不处理,或中间件跳过了 preflight)
很多“前端调不通”的问题,根源是后端没真正响应 OPTIONS,或者响应头拼写错误(比如写成 Access-Control-Allow-Orgin)。预检这一步,前端只能观察和适配,没法替后端兜底。











