之前面试有被问到: CORS是怎么解决跨域问题的, 之前一直只知道个大概,没有好好的复盘一下。趁着今天睡不着,写一篇文章记录一下自己对于CORS解决跨域问题的一些理解
那什么是跨域?
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
跨域是用来限制什么的?
简单来说, 跨域的概念来自于浏览器的同源策略。 目的就是为了保护网站的安全,防止用户信息泄露,防止身份伪造等。 这个又是另外一个知识点了,就不展开讲了
开始正题
我们经常在调试接口的时候, 经常看到类似于这样的情况
明明我只发送了一个请求, 为什么浏览器却发送了 两次请求, 究其原因其实就是发送的这个请求命中了CORS 复杂请求类型。 浏览器首先需要发送一个options请求跟服务器确认本次请求携带的信息是否在后端约束范围内
上面提到了几个关键:两次请求、 复杂请求、 options、 约束范围
一个一个来解读
两次请求
为什么发送两次请求?
当浏览器跨域访问另一个域名接口时, 会触发浏览器的同源策略, 如果后端采用的是CORS解决跨域问题时, 浏览器会先发送一个预检请求(options) 来跟后端端口进行校验,校验通过才会发送下一次请求。这就是为什么会出现两次请求的原因。
复杂请求 和 简单请求
首先明确一点,发送预检请求的前提是要命中 CORS 的复杂请求情况,那什么是 简单请求 和 复杂请求?
简单请求
-
使用下列方法之一
- GET
- HEAD
- POST
-
除了被用户代理自动设置的首部字段(例如 Connection ,User-Agent)和在 Fetch 规范中定义为 禁用首部名称 的其他首部,允许人为设置的字段为 Fetch 规范定义的 对 CORS 安全的首部字段集合。该集合为:
- Accept
- Accept-Language
- Content-Language
- Content-Type (需要注意额外的限制)
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
-
Content-Type 的值仅限于下列三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
满足以上所有条件才视为简单请求
options
options请求的作用是用于试探性的服务器响应是否正确,即是否能接受真正的请求,如果在options请求之后获取到的响应是拒绝性质的,例如500等http状态,那么它就会停止第二次的真正请求的访问 options请求不会发送类似于token这种开发者自定义的头部字段
约束范围
要满足后端定义的请求头才能通过options请求
- Access-Control-Allow-Origin: 哪些域名可以访问
- Access-Control-Allow-Headers: 允许携带哪些请求头
- Access-Control-Allow-Methods: 允许通过哪些方法访问
- Access-Control-Max-Age: 可以看成是当前请求缓存时间,单位为秒,设置为 -1 表示复杂请求必须进行options请求。Access-Control-Max-Age只针对当前请求
理论都讲完了, 接下来实操一下
首先操作一下后端什么都不设置的情况
这里我什么后端什么都没有设置 直接跨域了
看一下报错
提示 No Access_Control-Allow-Origin
接下来修改一下后端代码
// koa2代码, 不用管
ctx.set('Access-Control-Allow-Origin', '*')
看一下报错
没有报
No Access_Control-Allow-Origin
错误了
但是报
not allowed by Access-Control-Allow-Headers
错误
接下俩我们把 Access-Control-Allow-Headers 也放开
ctx.set('Access-Control-Allow-Headers', '*')
可以看到两次接口都请求成功了
接下来我们来看设置 Access-Control-Max-Age 的情况
// 设置options缓存3秒的情况
ctx.set('Access-Control-Max-Age', '3')
可以看到, 在第一次请求的时候发了两次请求, 5秒内再次请求只发送了一次请求, 5秒之后又发送了两次请求
以上就是这次的实操了。
上面的例子 Access-Control-Allow-Headers Access_Control-Allow-Origin 都是设置的 *, 线上肯定是不能这样用的。
还有 Access_Control-Allow-Methods, 大家可以自己去试一下
关于 Access-Control-Allow-Credentials 的情况说明:
如果设置了
Access-Control-Allow-Credentials: true
ccess_Control-Allow-Origin Access-Control-Allow-Headers Access_Control-Allow-Methods 就不能设置为 * 了, 否则还是会报跨域错误
大家可以自己去实操一下
关于CORS的东西我的理解暂时就这么多了, 有新的理解再继续码