📝 博客 · 2026-07-29 · ⏱ 12 分钟

什么是跨域(CORS)?前端必知

讲清楚同源策略、跨域原理、预检请求、常见跨域解决方案,前端面试必考。

一、同源策略

要理解跨域,先要理解"同源策略"。这是浏览器最核心的安全机制之一:浏览器不允许网页发起跨源的 HTTP 请求(更准确地说是允许发起,但不允许读取响应)。

什么是"同源"?两个 URL 满足以下三个条件都相同,才叫同源:

  1. 协议相同(http vs https)
  2. 域名相同(a.com vs b.com)
  3. 端口相同(80 vs 8080)

任意一个不同,就是跨域。

举几个例子:

当前页面 URL请求 URL是否跨域原因
http://a.com/pagehttp://a.com/api协议、域名、端口都同
http://a.com/pagehttps://a.com/api协议不同
http://a.com:80/pagehttp://a.com:8080/api端口不同
http://a.com/pagehttp://b.com/api域名不同
http://a.com/pagehttp://api.a.com/data子域不同

注意:a.comapi.a.com 是跨域的,即使它们是父子域关系。

二、为什么要有同源策略

假设没有同源策略,会发生什么?

你登录了银行 bank.com,浏览器存了 bank.com 的 cookie。然后你打开一个恶意网站 evil.com,这个网站的 JavaScript 可以向 bank.com 发请求——由于浏览器会自动带上 cookie,bank.com 会以为是你本人在操作,返回你的账户信息。evil.com 拿到数据后就能干坏事。

同源策略就是防止这种"一个网站偷读另一个网站数据"的情况。它规定:A 网站的 JavaScript 不能读取 B 网站返回的数据,即使请求发出去了,响应也被浏览器拦截。

三、CORS 是什么

CORS(Cross-Origin Resource Sharing,跨源资源共享)是 W3C 标准,它是在同源策略之上开的一个"白名单口子"。原理是:如果 B 网站的服务器在响应头里明确表示"我允许 A 网站访问",浏览器就放行

关键点:CORS 是浏览器和服务器的协作,主要由服务器配置。浏览器负责检查响应头,决定是否把数据交给 JavaScript。

四、简单请求 vs 预检请求

CORS 把请求分成两类:简单请求预检请求

简单请求

满足以下所有条件的请求是"简单请求":

条件允许的值
方法GET、HEAD、POST
自定义头只能是几个安全头(Accept、Content-Language 等)
Content-Type只能是三种:text/plainmultipart/form-dataapplication/x-www-form-urlencoded

简单请求直接发出去,服务器在响应头里加上 CORS 头,浏览器检查通过就放行。

预检请求

不满足简单请求条件的(比如用了 PUT/DELETE、发了 application/json、加了自定义头),浏览器会先发一个 OPTIONS 请求问服务器:"我能不能用这个方法、这些头来访问?"。这个 OPTIONS 请求就是预检请求(Preflight Request)

预检请求流程:

  1. 浏览器发 OPTIONS /api/users,带上这些头:
   Origin: http://a.com
   Access-Control-Request-Method: PUT
   Access-Control-Request-Headers: Content-Type, Authorization
  1. 服务器响应:
   Access-Control-Allow-Origin: http://a.com
   Access-Control-Allow-Methods: GET, POST, PUT, DELETE
   Access-Control-Allow-Headers: Content-Type, Authorization
   Access-Control-Max-Age: 86400
  1. 浏览器检查通过,再发真正的 PUT 请求
  2. 如果检查不通过,真正的请求不会发出,直接报错

对比表

维度简单请求预检请求
请求次数1 次2 次(OPTIONS + 实际请求)
触发条件满足上面所有条件不满足简单请求条件
是否能优化-可用 Max-Age 缓存预检

实际开发中,绝大多数 API 请求都是预检请求——因为现代前端都用 application/json 发数据,这本身就触发了预检。

五、关键响应头

CORS 相关的响应头有这些:

响应头作用
Access-Control-Allow-Origin允许哪些源访问(必填)
Access-Control-Allow-Methods允许哪些方法
Access-Control-Allow-Headers允许哪些请求头
Access-Control-Allow-Credentials是否允许带 cookie
Access-Control-Expose-Headers允许 JS 读哪些响应头
Access-Control-Max-Age预检结果缓存时间(秒)

最关键的是 Access-Control-Allow-Origin,它有几个常见写法:

# 允许所有源(不安全,不能配合 cookie)
Access-Control-Allow-Origin: *

# 允许单个源
Access-Control-Allow-Origin: https://a.com

# 动态返回请求方的 Origin(推荐)
Access-Control-Allow-Origin: http://a.com

六、带 Cookie 的跨域

默认情况下,跨域请求不会带 cookie。如果需要带(比如登录态跨域),需要:

  1. 前端:fetch(url, { credentials: "include" })axioswithCredentials: true
  2. 后端:响应头加 Access-Control-Allow-Credentials: true
  3. 后端:Access-Control-Allow-Origin 不能是 *,必须是具体域名

三个条件缺一不可。这是常见踩坑点——很多人配置了前两个,但 Allow-Origin: * 没改,浏览器仍然拒绝。

七、常见跨域解决方案

除了 CORS,历史上还有几种跨域方案:

1. CORS(推荐)

服务器配置响应头,浏览器自动处理。这是现代标准方案,绝大多数场景都应该用它。

2. JSONP

利用