Cors能干什么?为什么需要它?
一、先搞懂:为什么会有 “跨域”?CORS 又是什么?
要理解 CORS,首先得明白 “跨域” 的由来 —— 这一切都要从浏览器的 “安全规则” 说起。
1. 什么是 “跨域”?
浏览器为了保护用户数据安全,有一条核心规则叫 **“同源策略”**:只有当 “协议、域名、端口号” 三者完全一致时,前端页面才能正常请求服务器资源。如果三者中有任何一个不同,就属于 “跨域请求”,浏览器会默认拦截,不让请求成功。
举个例子:
- 前端页面地址:http://localhost:3000(协议 http,域名localhost,端口 3000)
- 后端接口地址 1:http://localhost:8080/api(端口不同,跨域)
- 后端接口地址 2:https://localhost:3000/api(协议不同,跨域)
- 后端接口地址 3:http://api.xxx.com/api(域名不同,跨域)
- 后端接口地址 4:http://localhost:3000/api(三者一致,同源,不跨域)
简单来说,“跨域” 就是前端和后端的 “地址不匹配”,浏览器出于安全考虑,不让它们直接通信。
2. CORS:跨域请求的 “通行证”
既然同源策略会拦截跨域请求,但实际开发中,前端和后端分开部署(比如前端用localhost,后端用云服务器)、前端调用第三方 API(比如调用微信支付接口、地图接口)都是很常见的场景,总不能因为跨域就不开发了吧?
这时候,CORS 就登场了—— 它是浏览器和服务器之间的一种 “约定”:如果服务器明确告诉浏览器 “我允许某个跨域地址的请求”,浏览器就会放行该请求,让数据正常传输。简单来说,CORS 就是服务器给跨域请求发的 “通行证”,有了这张通行证,浏览器就不会拦截请求了。
二、CORS 的工作原理:浏览器和服务器如何 “对话”?
CORS 的核心逻辑很简单:跨域请求时,浏览器会先 “询问” 服务器 “是否允许我这个地址的请求”,服务器回复 “允许” 后,浏览器再发送真正的请求数据。这个过程分为两种情况:“简单请求” 和 “预检请求”,我们分别来看。
1. 简单请求:直接 “询问 + 发送数据”
如果跨域请求满足以下条件,就属于 “简单请求”,浏览器会直接发送请求,并在请求头中带上 “自己的地址”(Origin 字段),让服务器判断是否允许:
- 请求方法是 GET、POST、HEAD 中的一种;
- 请求头只包含浏览器默认的字段(比如 Accept、Content-Type 等),且 Content-Type 的值只能是 text/plain、multipart/form-data、application/x-www-form-urlencoded 中的一种。
简单请求的流程:
- 前端发送请求,请求头中携带Origin: http://localhost:3000(告诉服务器 “我来自这个地址”);
- 服务器收到请求后,检查 Origin 字段:如果允许该地址跨域,就会在响应头中添加Access-Control-Allow-Origin: http://localhost:3000(告诉浏览器 “我允许这个地址的请求”);
- 浏览器收到响应后,看到响应头中有允许自己地址的字段,就会放行数据,前端正常拿到返回结果;如果没看到该字段,就会弹出 CORS 报错,拦截数据。
2. 预检请求:先 “申请”,再 “发送数据”
如果跨域请求不满足 “简单请求” 的条件(比如请求方法是 PUT、DELETE,或者请求头中自定义了字段,比如 Token),浏览器会先发送一个 “预检请求”(OPTIONS 请求),相当于先向服务器 “申请”:“我接下来要发一个跨域请求,方法是 PUT,还会带自定义头,你允许吗?”,服务器同意后,才会发送真正的业务请求。
预检请求的流程:
- 前端先发送 OPTIONS 请求,请求头中携带 3 个关键字段:
- Origin: http://localhost:3000(我的地址);
- Access-Control-Request-Method: PUT(我接下来要发的请求方法);
- Access-Control-Request-Headers: Token(我接下来要带的自定义头);
- 服务器收到 OPTIONS 请求后,检查这 3 个字段,然后在响应头中返回允许的信息:
- Access-Control-Allow-Origin: http://localhost:3000(允许你的地址);
- Access-Control-Allow-Methods: PUT, GET, POST(允许你用这些方法);
- Access-Control-Allow-Headers: Token(允许你带这个自定义头);
- Access-Control-Max-Age: 86400(这次允许的有效期是 24 小时,24 小时内不用再发预检请求);
- 浏览器收到 OPTIONS 响应后,确认服务器允许,就会发送真正的 PUT 请求,携带 Token 和业务数据;
- 服务器处理 PUT 请求,返回业务数据,响应头中依然要带上Access-Control-Allow-Origin: http://localhost:3000,浏览器确认后放行数据。
简单来说:“简单请求” 是 “一次请求”,“预检请求” 是 “两次请求”(先 OPTIONS 申请,再业务请求),但核心都是 “服务器允许,浏览器才放行”。