跨域与 CORS 速查

4 个速查板块 · 关联 4 款站内工具 · 数据最后核对 2026-10-05

同源策略到底在防什么、什么样的请求会触发预检、Access-Control-* 头部怎么配才不会报错,以及几个必踩的坑。

跨域报错几乎是每个前端都会碰到的第一个「玄学问题」:接口用工具能调通,浏览器里就是不行。原因在于同源策略——浏览器主动限制网页去读取其他源的响应,这是一道安全闸门,而不是服务器坏了。

CORS(跨源资源共享)是这道闸门的官方放行机制:由服务器在响应头里明确声明「我允许哪些来源读我的数据」。所以跨域问题几乎总是要在服务端改,前端改不了。

1同源策略:三个维度必须全同

判断两个地址是否同源,只看「协议 + 主机 + 端口」三件事,任意一项不同就是跨源。路径与查询参数不参与判断。

当前页面请求目标是否同源原因
https://a.comhttps://a.com/api同源协议、主机、端口全同,路径不同不影响
https://a.comhttp://a.com/api跨源协议不同(https 与 http)
https://a.comhttps://b.com/api跨源主机不同
https://a.comhttps://a.com:8080/api跨源端口不同(默认 443 与 8080)
https://a.comhttps://api.a.com跨源子域名也算不同主机
https://a.comhttps://a.com:443/api同源省略端口时按协议默认端口补齐,与显式 443 等价
页面打开方式file:// 协议跨源本地直接打开 HTML 时源为空,很多接口会因此被拦

同源策略限制的是「网页读取响应内容」,不是「请求发不出去」。跨域请求实际已经到达服务器并执行了(除非是预检被拒),只是响应内容不给页面读。所以「跨域报错但服务端日志有记录」是完全正常的。

2简单请求与预检请求

CORS 分两种处理方式,判断依据是「请求本身有多特殊」。越简单的请求越少一次往返。

类别触发条件流程代价
简单请求方法为 GET / HEAD / POST,且头部仅限安全列表字段,Content-Type 仅限表单类三种直接发出,浏览器看响应头决定是否放行一次往返
预检请求方法为 PUT / DELETE / PATCH 等,或 Content-Type: application/json,或带了自定义头部先用 OPTIONS 问服务器允不允许,通过后才发真实请求多一次往返
带凭证请求设置了 withCredentials 或 credentials: include额外要求 Allow-Origin 不能是 *,且需 Allow-Credentials配置更严格
预检缓存服务器返回 Access-Control-Max-Age在有效期内同源的同类请求不再重复预检减少 OPTIONS 次数
被拒之后预检未通过浏览器直接拦截,真实请求不会发出前端只看到 CORS 报错,服务端看不到真实请求

开发时最常见的跨域场景是「本地 `localhost:3000` 调线上 `api.xxx.com`」。这类问题最简单的解法是开发服务器配一层代理,让请求同源发出;上线后同域部署则根本不存在跨域。比在生产环境放开 `*` 安全得多。

3CORS 响应头对照

服务器通过这些响应头声明放行规则。注意「请求头」与「响应头」的区别:Origin 是浏览器发出的,其余都是服务器返回的。

头部作用取值说明
Access-Control-Allow-Origin允许哪些源读取响应可以是具体的源或 *;带凭证时不能用 *
Access-Control-Allow-Methods允许哪些方法如 GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers允许哪些请求头自定义头必须在这里列出,否则预检失败
Access-Control-Allow-Credentials是否允许携带凭证设为 true 时 Allow-Origin 必须是具体源
Access-Control-Max-Age预检结果缓存多久单位秒,减少 OPTIONS 请求次数
Access-Control-Expose-Headers允许页面读取哪些自定义响应头默认只能读少数几个基础头
Vary: Origin告诉缓存按 Origin 区分副本多源动态返回时必须加,否则 CDN 会串源

如果 `Allow-Origin` 需要按请求的 `Origin` 动态回显(比如支持多个白名单域名),务必同时返回 `Vary: Origin`。否则 CDN 或代理可能把给 A 站的响应缓存下来发给 B 站,造成安全与功能双重问题。

4常见跨域报错对照

浏览器只在控制台给一行报错,成因却各不相同。看关键短语就能定位。

`No 'Access-Control-Allow-Origin' header`
服务端没有返回这个头。检查是否真的配置了 CORS,以及请求是否真的打到了预期的服务
`credentials flag is true, but Allow-Origin is *`
带凭证时不能用通配符。把 Allow-Origin 改成回显具体的 Origin
`does not pass access control check`(预检失败)
Allow-Methods 或 Allow-Headers 没覆盖实际用到的方法或头。补齐即可
`Response to preflight request doesn't pass`
OPTIONS 请求没被正确处理。不少框架需要显式放行 OPTIONS 路由,或中间件顺序不对
`Redirect is not allowed for a preflight request`
预检不支持 302 / 301 跳转。把 CORS 处理放在跳转之前
浏览器正常但工具正常
命令行工具不受同源策略约束,所以「Postman 能调通」不能说明浏览器也能

关于「跨域与 CORS 速查」的常见问题

什么是同源策略,为什么要有它?

同源策略是浏览器的安全机制:一个网页只能读取与它「协议、主机、端口完全一致」的源的响应内容。它的作用是防止恶意页面在用户已登录某个网站的情况下,偷偷去读取那个网站的数据——比如一个钓鱼页面用用户浏览器里的登录状态去请求网银接口,如果没有同源策略,它就能读到余额信息。这个策略限制的是「读取响应」,不是「发出请求」,所以跨域请求实际会到达服务器,只是响应内容不给当前页面读。

为什么我的请求会多发一次 OPTIONS?

这是 CORS 的预检机制。当请求不属于「简单请求」时——例如用了 PUT / DELETE 方法、Content-Type 是 application/json、或带了自定义请求头——浏览器会先发一个 OPTIONS 请求询问服务器「允许这个源用这个方法、带这些头吗」,得到肯定答复后才发真正的请求。所以你会看到两条记录。解决办法有两个:一是服务器返回 Access-Control-Max-Age,让浏览器缓存预检结果,减少重复的 OPTIONS;二是把请求改造成简单请求(如用表单编码),但不是所有场景都可行。

带 Cookie 的跨域请求为什么总是失败?

因为带凭证的跨域有额外的硬性限制。首先 Access-Control-Allow-Credentials 必须显式设为 true;其次 Access-Control-Allow-Origin 不能是通配符 *,必须回显请求的具体 Origin 值(或精确匹配白名单);另外前端也要显式开启凭证发送(fetch 里设 credentials: include,或 XHR 里设 withCredentials = true)。这三点缺任何一个都会失败。还要注意 Cookie 自身的 SameSite 属性也可能拦下跨站请求,如果 Cookie 设了 SameSite=Strict,跨站场景下根本不会被带上。

跨域问题该在前端解决还是后端解决?

本质上必须在服务端解决,因为 CORS 是服务器通过响应头声明放行规则的,前端改不了服务端。前端能做的主要是规避:开发阶段配置开发服务器代理,让请求从同源发出,从而不触发跨域;或者把请求发到自己的后端,由后端再去调用第三方接口(服务端之间不受同源策略约束)。上线阶段最稳的是应用与接口同域部署,或至少同主域,从根本上避免跨域。不建议在生产环境把 Allow-Origin 放开成 *,也不建议用把浏览器安全策略关掉的方式「解决」问题。

内容标识:本页内容由人工智能辅助生成,并经人工核对与编辑。详见 人工智能生成内容标识说明。
内容说明:本页速查数据由本站自行整理,事实性内容以对应官方规范与文档为准,未复制第三方速查表或百科的表述。数据最后核对日期:2026-10-05。若发现错误或已更新的标准,欢迎通过页脚反馈入口告知。