Skip to content

CORS

CORS 是浏览器为跨源 HTTP 请求提供的一套协商机制,全称是 Cross-Origin Resource Sharing,中文通常叫“跨源资源共享”。

它不是服务端框架特性,而是浏览器基于同源策略增加的一层放行规则。

为什么会有 CORS

浏览器默认受同源策略约束。当前页面如果来自:

md
https://app.example.com

那么直接请求:

md
https://api.example.com

就属于跨源请求。浏览器不会因为“能发出请求”就默认允许 JS 读取响应结果。

什么叫跨源

协议、主机、端口任意一个不同,就算跨源。

md
https://app.example.com
https://app.example.com:8080 // 跨源
http://app.example.com // 跨源
https://api.example.com // 跨源

CORS 的基本思路

浏览器在跨源请求时会自动附带 Origin 请求头,服务端通过响应头声明是否允许当前来源访问。

http
Origin: https://app.example.com

服务端如果允许,可以返回:

http
Access-Control-Allow-Origin: https://app.example.com

简单请求

部分跨源请求属于“简单请求”,浏览器会直接发送,再根据响应头判断是否允许前端读取结果。

常见条件包括:

  • 方法是 GETHEADPOST
  • 自定义请求头较少
  • Content-Type 属于浏览器规定的简单类型

预检请求

如果请求不属于简单请求,浏览器会先自动发一个 OPTIONS 请求,这就是预检请求。

典型触发场景:

  • 使用 PUTPATCHDELETE
  • 带自定义请求头,如 Authorization
  • Content-Type: application/json
http
OPTIONS /user HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorization

服务端需要明确回应:

http
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization

如果预检没通过,真正的业务请求根本不会发出。

常见响应头

Access-Control-Allow-Origin

允许的来源。

http
Access-Control-Allow-Origin: https://app.example.com

Access-Control-Allow-Methods

允许的 HTTP 方法。

http
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS

Access-Control-Allow-Headers

允许的请求头。

http
Access-Control-Allow-Headers: Content-Type, Authorization

Access-Control-Allow-Credentials

是否允许携带凭证,如 Cookie。

http
Access-Control-Allow-Credentials: true

Access-Control-Max-Age

预检结果缓存时长。

http
Access-Control-Max-Age: 600

前端:

js
fetch('https://api.example.com/user', {
  credentials: 'include',
})

服务端:

http
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

注意两点:

  • Access-Control-Allow-Origin 不能写 *
  • Cookie 本身还要满足 SameSite 等策略限制

常见误区

“后端已经返回数据了,为什么前端还是报跨域”

很多情况下请求其实已经到达服务端,也已经拿到响应,只是浏览器因为 CORS 校验失败,不允许前端脚本读取。

“跨域是请求发不出去”

不完全准确。更准确地说,是浏览器限制前端脚本读取跨源响应。

“本地没问题,线上突然跨域”

常见原因:

  • 本地用了 dev server 代理
  • 线上域名和端口变化
  • 线上请求附带了额外请求头,触发了预检

开发建议

  • 前后端联调时先明确:是同源、跨源,还是经过代理后的伪同源。
  • 出现跨域问题时同时看请求头、响应头和浏览器控制台,不要只盯代码。
  • 需要鉴权时,把 CORSCookieSameSitecredentials 一起排查。

基于 MIT 许可发布