外观
跨域是什么,CORS 怎么工作?
浏览器的同源策略规定:协议、主机、端口有一个不同,脚本就不能随意读另一个源的响应。CORS 是服务器用响应头明确允许某个源来读。它限制的是「脚本能不能读」,不是「请求能不能发出去」。
原理
简单请求会直接发出,例如 GET、POST、HEAD,且自定义头很少,Content-Type 属于 text/plain、application/x-www-form-urlencoded、multipart/form-data 之一。响应里要有 Access-Control-Allow-Origin,其值是具体源或 *。对不上的话,脚本拿不到响应,浏览器控制台会报 CORS 错误。
不满足简单请求条件时,浏览器先发 OPTIONS 预检,询问是否允许这个方法、这些头。服务器用下面几个头回答:
Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-HeadersAccess-Control-Max-Age:预检结果可以缓存多久
要带 Cookie 时,前端把 fetch 的 credentials 设为 include,服务器返回 Access-Control-Allow-Credentials: true,并且 Allow-Origin 必须是具体源,不能是 *。
开发环境常用开发服务器把接口代理到同主机,浏览器看到的是同源,从而绕开这套检查。生产环境要在真正的接口上配置 CORS,或者由自己的服务端转发。
JSONP 利用的是 script 标签不受这套读取限制,只能发 GET,而且等于在页面里执行别人的脚本。现在不要用它做接口方案。
追问
为什么 Postman 没有跨域问题?
同源策略是浏览器给网页脚本加的。Postman、服务端和 curl 不走这套检查。
CORS 能代替 CSRF 防护吗?
不能。跨站表单照样能把请求发出去。见 CSRF。
易错点
- 端口不同也是跨源,
localhost:5173和localhost:3000不同源。 - 预检失败时,业务请求不会发出,抓包里往往只有
OPTIONS。 Allow-Origin: *和携带凭证不能同时使用。