javascript如何与后端API交互_cors和预检请求如何处理【教程】

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

JavaScript 无法绕过浏览器的同源策略直接请求不同源的后端 API,CORS 不是前端能“解决”的问题,而是必须由后端配置响应头;但前端可以主动规避预检(preflight)或适配其行为。

为什么 fetch 会触发 OPTIONS 预检请求

fetch 发出的请求满足以下任一条件时,浏览器会在发实际请求前自动发送一个 OPTIONS 请求(即预检):

  • 使用了除 GETHEADPOST 之外的 HTTP 方法(如 PUTDELETE
  • 设置了自定义请求头(如 AuthorizationX-Request-ID
  • Content-Type 不是以下三种之一:text/plainmultipart/form-dataapplication/x-www-form-urlencoded

预检失败(如后端未返回 Access-Control-Allow-Origin 等头)会导致整个请求被浏览器拦截,控制台报错 Failed to fetchNo 'Access-Control-Allow-Origin' header

如何让前端不触发预检(简单场景适用)

如果后端暂时无法改 CORS 配置,可尝试让请求“降级”为简单请求:

  • 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:3000http://127.0.0.1:3000 被视为不同源,也需分别配置。

调试预检失败最有效的三步

遇到 CORS 报错,别急着改前端代码:

  • 打开浏览器 DevTools → Network → 找到那个 OPTIONS 请求 → 看 Response Headers 是否含 Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers
  • 检查该 OPTIONS 响应状态码是否为 200(不是 404405
  • 确认后端是否对 OPTIONS 请求做了特殊拦截(如某些框架默认不处理,或中间件跳过了 preflight)

很多“前端调不通”的问题,根源是后端没真正响应 OPTIONS,或者响应头拼写错误(比如写成 Access-Control-Allow-Orgin)。预检这一步,前端只能观察和适配,没法替后端兜底。