主题
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简单请求
部分跨源请求属于“简单请求”,浏览器会直接发送,再根据响应头判断是否允许前端读取结果。
常见条件包括:
- 方法是
GET、HEAD、POST - 自定义请求头较少
Content-Type属于浏览器规定的简单类型
预检请求
如果请求不属于简单请求,浏览器会先自动发一个 OPTIONS 请求,这就是预检请求。
典型触发场景:
- 使用
PUT、PATCH、DELETE - 带自定义请求头,如
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.comAccess-Control-Allow-Methods
允许的 HTTP 方法。
http
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONSAccess-Control-Allow-Headers
允许的请求头。
http
Access-Control-Allow-Headers: Content-Type, AuthorizationAccess-Control-Allow-Credentials
是否允许携带凭证,如 Cookie。
http
Access-Control-Allow-Credentials: trueAccess-Control-Max-Age
预检结果缓存时长。
http
Access-Control-Max-Age: 600携带 Cookie 时要注意什么
前端:
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 代理
- 线上域名和端口变化
- 线上请求附带了额外请求头,触发了预检
开发建议
- 前后端联调时先明确:是同源、跨源,还是经过代理后的伪同源。
- 出现跨域问题时同时看请求头、响应头和浏览器控制台,不要只盯代码。
- 需要鉴权时,把
CORS、Cookie、SameSite、credentials一起排查。
