极简工具箱

免费在线工具 · 本地计算 · 无需上传

CORS 跨域报错怎么解:预检、凭证与 Access-Control-Allow-Origin

前端报「blocked by CORS policy」,后端说「我加了 Allow-Origin: * 啊」。加上凭证、加上自定义头之后,`*` 就不管用了——这是跨域最常见的死结。

广告位(百度联盟)

一、同源策略在防什么

源 = 协议 + 域名 + 端口,三者全同才算同源。https://a.com 与 http://a.com 不同源,a.com:443 与 a.com:8443 也不同源。

同源策略限制的是读取响应,不是「发请求」。跨域的 POST 请求往往已经到达服务器并被执行了,只是浏览器不把响应交给 JS。所以「跨域请求没生效」的判断要谨慎——去看服务端日志,可能已经写库了。

二、简单请求 vs 预检请求

满足以下全部条件的是简单请求,直接发出,不预检:

其余情况(PUT/DELETE、Content-Type: application/json、自定义头如 Authorization)都会先发一个 OPTIONS 预检,服务端必须正确响应,浏览器才会发真实请求。

这是很多人踩的坑:POST + application/json 不是简单请求,会触发预检;而 Nginx 没配 OPTIONS 直接返回 405,前端就报跨域。

三、响应头怎么配

Access-Control-Allow-Origin: https://www.it586.cn
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

规则:

四、带 Cookie 的三件套

fetch(url, { credentials: 'include' })
Access-Control-Allow-Origin: https://www.it586.cn
Access-Control-Allow-Credentials: true

同时前端 Cookie 要设 SameSite=None; Secure(跨站携带 Cookie 的前提,且必须 HTTPS)。三者缺一不可,缺任何一个浏览器都会静默丢弃 Cookie。

另外 Allow-Origin 此时**不能是 ***,也不能是「先回 * 再回具体源」——响应头只能有一个值。

五、Nginx 配置示例

location /api/ {
    if ($request_method = OPTIONS) {
        add_header Access-Control-Allow-Origin  $http_origin always;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
        add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
        add_header Access-Control-Allow-Credentials true always;
        add_header Access-Control-Max-Age 86400 always;
        return 204;
    }
    add_header Access-Control-Allow-Origin  $http_origin always;
    add_header Access-Control-Allow-Credentials true always;
}

always 很重要:不加它,4xx/5xx 响应不会带 CORS 头,前端只能看到「跨域错误」,看不到真正的 500。

六、排查顺序

  1. 看 Network 里有没有 OPTIONS 请求,状态码是多少(405/404 说明服务端没处理预检)。
  2. 看响应头 Allow-Origin 是否与页面源完全一致(含协议、端口,末尾不能有斜杠)。
  3. 带 Cookie 时确认 Allow-Credentials: true 且 Origin 不是 *。
  4. 检查是否有多个 CORS 头重复(Nginx 和 应用各加一次,浏览器会拒绝)。
  5. 确认请求真的跨域——很多时候是写错了协议或端口。

七、什么时候不该用 CORS

开发阶段更简单的方式是代理:前端 dev server 把 /api 代理到后端,浏览器看到的是同源请求,完全不涉及 CORS。生产环境如果前后端同域部署,也就不需要 CORS。只有「前端独立域名 + 后端 API 域名」才必须配。

小结

CORS 是浏览器行为,服务端只是「声明允许谁读」。JSON 请求必预检、OPTIONS 要返回 2xx、带 Cookie 不能用 *、always 让错误响应也带头。开发期用代理比调 CORS 省事。

本文相关工具(本地计算,无需上传)

更多使用教程